.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! Smile

OK, let’s first create a “console” .NET Core app. In Visual Studio 2015, create a new project of type WebClass Library (Package):

image

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:

image

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! Winking smile

 

                             

19 Comments

  • I followed you code, but my `ServiceProvider` is null, and therefor the `Main` fails.

    I do not really understand how the `ServiceProvider` property is set, because how does the `Constructor` run before `Main`?

  • Olver:
    You're doing something different, that's all I can say.
    What runtime are you using? Are you running under VS or DNX?
    I can send you my project, if you like. Or, you can just use PlatformServices.Default

  • Yes, please send.. :) I can use `PlatformServices.Default` but running this code: https://gist.github.com/TryingToImprove/494dc73def916849eee0 through Visual Studio will not set the `ServiceProvider`..

    I am using dnx version 1.0.0-rc1-update1 on Windows

  • Pretty sweet. Lots of cool stuff coming out. Except json that is. Just say no to json. ;)
    https://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/9347001-improve-reboot-visual-studio-project-system.

    Also, I have learned a lot in the past few months about static singletons (especially for service location as described in this article). While they are just fine for single-threaded applications, in multi-threaded applications that might access resources at the same time (or need a different configured container) this turns into a headache. As an example, I switched my codebase testing over to xUnit2.0 which runs parallel threads by default. All my code was hinged through ServiceLocator.Current and I have basically spent the past 3-4 months getting schooled in how to make everything thread-friendly (hint: no more singletons).

  • Can you provide code on github or similar? I can't get this sample working either due to ServiceProvider being null...

  • And PlatformServices.Default?

  • PlatformServices.Default does indeed have a value - it appears that my constructor isn't being called so IServiceProvider is never injected??

  • Guys,
    You can find the source code here:
    https://onedrive.live.com/redir?resid=450C015FC418DE2!96839&authkey=!ABFwBt57V7AkzbE&ithint=file%2czip
    Works perfectly on my machine (now, where did I hear this?).

  • Hi,

    `PlatformServices.Default` was not null, but the `Program()` constructor never got hit..

    I asked in a chat-forum on jabbr about this, and Matthew_Abbott answered:

    >> This form of constructor injection is no longer supported, it was originally a feature of DNX apps, but since moving to .NET CLI, the entry point semantics have been cleaned up and now model classic console applications (everything is a console app). If you are trying to get an instance of IServiceProvider in your console app, you can spin your own up (I've blogged about this: http://www.inversionofcontrol.co.uk/asp-net-core-1-0-dependency-injection-what-is-is-and-what-it-is-not-2/ -> "Use outside of ASP.NET Core")

    So I guess this will not work with the new .NET CLI, but it have worked with a earlier version of DNX.. :)

  • Oliver,
    It works with DNX, and it is documented: http://docs.asp.net/en/latest/dnx/overview.html. Works perfectly with runtime 1.0.0-rc2-16357.
    I don't know about the future, but I will find out and update the post with this.

  • good site.thanks for post

  • Also, I have learned a lot in the past few months about static singletons (especially for service location as described in this article). While they are just fine for single-threaded applications, in multi-threaded applications that might access resources at the same time (or need a different configured container) this turns into a headache. As an example, I switched my codebase testing over to xUnit2.0 which runs parallel threads by default. - See more at: http://weblogs.asp.net/ricardoperes/net-core-console-applications#sthash.a4EPlMQk.dpuf

  • Yes, please send.. :) I can use `PlatformServices.Default` but running this code: https://gist.github.com/TryingToImprove/494dc73def916849eee0 through Visual Studio will not set the `ServiceProvider`.. - See more at: http://weblogs.asp.net/ricardoperes/net-core-console-applications#sthash.Gh68q1QL.dpuf

  • Yes, please send.. :) I can use `PlatformServices.Default` but running this code: https://gist.github.com/TryingToImprove/494dc73def916849eee0 through Visual Studio will not set the `ServiceProvider`.. - See more at: http://weblogs.asp.net/ricardoperes/net-core-console-applications#sthash.Gh68q1QL.dpuf

  • good site

  • Yes, this no longer works. Constructor injection in Program class is no longer supported.

  • See https://github.com/aspnet/Announcements/issues/106

  • hi admin good site

  • Your site is really nice Thanks

Add a Comment

As it will appear on the website

Not displayed

Your website