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()
;
}
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();
}
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");
}
}