Search code examples
c#asp.net-core.net-coreconsole-application

How to run .NET Core Console app using generic host builder


I am trying to figure out how to use hostbuilder pattern to run a console app (not a windows service). Intent is to keep the flow as similar to a WebApi to keep development practices similar. I have seen samples for using HostedService or BackGroundService, where they want to run it as a windows service. But If I am looking to run a simple console app, where do I specify my entrypoint class and method? From hostbuilder.Build(), I can see Run() and RunAsync() methods. But I am unable to figure out what will it execute?

I have seen other examples of where you can create servicecollection and then use serviceprovider.GetService().SomeMethod() to start the process. But that kind of deviates from what we want to do. So please suggest how to specify startup process. We are using 3.1 .Net Core.

class Program
{
    static async void Main(string[] args)
    {
        var host = CreateHostBuilder(args).Build();
        await host.RunAsync();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureServices((hostBuilderContext, serviceCollection) => new Startup(hostBuilderContext.Configuration).ConfigureServices(serviceCollection))
        .UseSerilog()
        ; 

}

Solution

  • EDIT: An update for .NET 6 is below ↓
    Not much has changed with .NET 7 or .NET 8.


    I'd start off with the default worker template. It comes with necessary packages pre-installed. If you already have a project, install Microsoft.Extensions.Hosting package.

    dotnet new worker -n MyCli
    

    Then open up the Program.cs and build the host. Remove the Worker hosted service if you don't want to go with the hosted service route.

    public class Program
    {
        public static void Main(string[] args)
        {
            var host = CreateHostBuilder(args).Build();
        }
    
        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureServices((hostContext, services) =>
                {
                    // remove the hosted service
                    // services.AddHostedService<Worker>();
    
                    // register your services here.
                });
    }
    

    Build your logic:

    internal class MyService
    {
        // you can also inject other services
        private ILogger<MyService> _logger;
    
        public MyService(ILogger<MyService> logger)
        {
            _logger = logger;
        }
    
        public void DoSomething()
        {
            _logger.LogInformation("Doing something");
        }
    }
    

    Then register the class inside .ConfigureServices method

    Host.CreateDefaultBuilder(args)
        .ConfigureServices((hostContext, services) =>
        {
            services.AddTransient<MyService>();
        });
    

    Now you can resolve and call it inside the Main method:

    public static void Main(string[] args)
    {
        var host = CreateHostBuilder(args).Build();
        var myService = host.Services.GetRequiredService<MyService>();
        myService.DoSomething();
    }
    

    .NET 6+ update

    With .NET 6, boilerplate is reduced significantly. We can rewrite our Program.cs as:

    using Microsoft.Extensions.Hosting; // Requires NuGet package
    
    var host = Host.CreateDefaultBuilder(args)
        .ConfigureServices(services => { services.AddTransient<MyService>(); })
        .Build();
    
    var my = host.Services.GetRequiredService<MyService>();
    await my.ExecuteAsync();
    
    class MyService
    {
        private readonly ILogger<MyService> _logger;
    
        public MyService(ILogger<MyService> logger)
        {
            _logger = logger;
        }
    
        public async Task ExecuteAsync(CancellationToken stoppingToken = default)
        {
            _logger.LogInformation("Doing something");
        }
    }