.NET Core 2.1 introduced new Generic Host, which allows to host non-HTTP workloads with all benefits of Web Host. Currently, there is no much information and recipes with it
I'll share some patterns I think works very well for non-WebHost projects.
namespace MyNamespace
{
public class MyService : BackgroundService
{
private readonly IServiceProvider _serviceProvider;
private readonly IApplicationLifetime _appLifetime;
public QbdSkuVaultIntSchedulerService(
IServiceProvider serviceProvider,
IApplicationLifetime appLifetime)
{
_serviceProvider = serviceProvider;
_appLifetime = appLifetime;
}
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
_appLifetime.ApplicationStopped.Register(OnStopped);
return RunAsync(stoppingToken);
}
private async Task RunAsync(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
using (var scope = _serviceProvider.CreateScope())
{
var runner = scope.ServiceProvider.GetRequiredService<IMyJobRunner>();
await runner.RunAsync();
}
}
}
public void OnStopped()
{
Log.Information("Window will close automatically in 20 seconds.");
Task.Delay(20000).GetAwaiter().GetResult();
}
}
}
A couple notes about this class:
Set up the host in Main( string[] args ) so that it shuts down gracefully when CTRL+C / SIGTERM is called:
IHost host = new HostBuilder()
.ConfigureServices( ( hostContext, services ) =>
{
services.AddHostedService<MyService>();
})
.UseConsoleLifetime()
.Build();
host.Run(); // use RunAsync() if you have access to async Main()
I've found this set of patterns to work very well outside of ASP.NET applications.
Be aware that Microsoft has built against .NET Standard so you don't need to be on .NET Core to take advantage of these new conveniences. If you're working in Framework just add the relevant NuGet packages. The package is built against .NET Standard 2.0 so you need to be on Framework 4.6.1 or above. You can find the code for all of the infrastructure here and feel free to poke around at the implementations for all the abstractions you are working with: https://github.com/aspnet/Extensions
You need IApplicationLifetime
. This provides you with all the needed information about application start and shutdown. You can even trigger the shutdown with it via appLifetime.StopApplication();
Look at https://github.com/aspnet/Docs/blob/66916c2ed3874ed9b000dfd1cab53ef68e84a0f7/aspnetcore/fundamentals/host/generic-host/samples/2.x/GenericHostSample/LifetimeEventsHostedService.cs
Snippet(if the link becomes invalid):
public Task StartAsync(CancellationToken cancellationToken)
{
appLifetime.ApplicationStarted.Register(OnStarted);
appLifetime.ApplicationStopping.Register(OnStopping);
appLifetime.ApplicationStopped.Register(OnStopped);
return Task.CompletedTask;
}
In Startup.cs
, you can terminate the application with the Kill()
method of the current process:
public void Configure(IHostApplicationLifetime appLifetime)
{
appLifetime.ApplicationStarted.Register(() =>
{
Console.WriteLine("Press Ctrl+C to shut down.");
});
appLifetime.ApplicationStopped.Register(() =>
{
Console.WriteLine("Shutting down...");
System.Diagnostics.Process.GetCurrentProcess().Kill();
});
}
Program.cs
Don't forget to use UseConsoleLifetime()
while building the host.
Host.CreateDefaultBuilder(args).UseConsoleLifetime(opts => opts.SuppressStatusMessages = true);