.NET Core Console Applications
Updated
.NET Core is not just for web apps, and some people tend to forget about it! Well, this post is about that!
OK, let’s first create a “console” .NET Core app. In Visual Studio 2015, create a new project of type Web – Class Library (Package):
After you do that, if you want to run your app inside VS, you need to change a few things. Go to project.json and change the library from dotnet5.4 to dnxcore50:
If you want to get information from the environment, you need to obtain a reference to the APIs that supply that information. So, add references to Microsoft.Extensions.DependencyInjection.Abstractions and Microsoft.Extensions.PlatformAbstractions (you can see that in the above picture).
Now, things get a bit weird… you need to do something rather dumb:
public class Program
{
public static IServiceProvider ServiceProvider { get; private set; }
public Program(IServiceProvider serviceProvider)
{
ServiceProvider = serviceProvider;
}
static void Main(string [] args)
{
var re = ServiceProvider.GetService<IRuntimeEnvironment>(); //for operating system, architecture and runtime info
var ae = ServiceProvider.GetService<IApplicationEnvironment>(); //for application path, name, version, configuration info
}
}
Some “context” services are available through the dependency injection framework, available as an IServiceProvider instance, but you can also get a pointer to them through the PlatformServices.Detault property:
var ae = PlatformServices.Default.Application;
var re = PlatformServices.Default.Runtime;
Here you will find these services:
-
IApplicationEnvironment: the application context
-
IRuntimeEnvironment: runtime context
-
IAssemblyLoaderContainer: for adding assembly loaders
-
IAssemblyLoadContextAccessor: a façade to the assembly loaders, for loading assemblies on demand
-
ILibraryManager: for introspecting the referenced libraries
You can see that the .NET Core team took the decision to inject these into the constructor of types that it builds, but the funny think is that there is no need for an actual instance of the Program class, as all the runtime needs is the static Main method! It seems a bit silly that we need to keep things in static fields, but I think they do not want to have static access points to these in the core framework, so it’s up to use how we are going to use them. Rest assured, the constructor will be called before Main!
Update: According to a Microsoft announcement here, from RC2 onwards, .NET Core will not support constructor injection in the Program class, so, the way to go will be through PlatformServices and CompilationServices. However, it still works in the DNX 1.0.0-rc2-16357 runtime.
If you need to use System.Console, which you will likely do, in a console, app, you need to add a reference to the System.Console Nuget package, for the dnxcore50 framework.
For more advanced stuff, like, for example, accessing databases – any database as long as it is SQL Server… - you need to add the System.Data.SqlClient Nuget package. The code looks exactly the same as it would in plain old .NET:
using (var con = new SqlConnection())
using (var cmd = con.CreateCommand())
{
con.ConnectionString = @"Data Source=.\SQLEXPRESS; Integrated Security=SSPI";
con.Open();
cmd.CommandText = "SELECT GetUtcDate()";
var now = (DateTime) cmd.ExecuteScalar();
Console.WriteLine(now);
}
Finally, you need to add a command to it, so that you can actually run it. Add a command, say, “run”, to the commands section of project.json:
"commands": {
"run": "My.ConsoleApp"
}
Here, My.ConsoleApp should the name (and folder) of your project, these should match.
And this is about it. If you want to pass parameters to your program, you can do so in the call to dnx, after the command:
dnx run this and that
“this and that” will be passed as arguments to the Main method.
For running dnx, make sure your runtime is set appropriately, by using dnvm.
Enjoy .NET Core console!