Hosted Worker Service on .NET Framework
One of the nifty new templates for .NET Core will spit out a console app that runs a "Hosted" worker service. That is, code that runs in the background and takes advantage of all the new configuration and dependency injection APIs that were originally introduced along with ASP.NET Core. This is all documented over on docs.microsoft.com.
However, if there is a need for it, it is still possible to setup a .NET Framework application that takes advantage of all of the same APIs and hosting model. (Note: the full working sample for this is posted on my Github repo).
The first thing to do is, to create a regular ol' .NET Framework Console app. Then add in the following Nugets (I also like to go ahead and convert my project to use Package References and tidy things up a bit):
Install-Package Microsoft.Extensions.Configuration.UserSecrets
Install-Package Microsoft.Extensions.Hosting
Install-Package Microsoft.Extensions.Hosting.WindowsServices
The WindowsService package is optional, but if you're planning on running your worker service as a Windows Service then you'll have to bring that in as well.
Next, let's go ahead an create a Worker class. The example doesn't do anything besides print a message every time it runs, but it also demonstrates that we'll be able to have the hosting service inject both an ILogger and an IConfiguration instance.
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
private readonly int _timeout;
public Worker(ILogger<Worker> logger, IConfiguration config)
{
_logger = logger;
_timeout = config.GetValue("WorkerTimeout", 5000);
}
protected async override Task ExecuteAsync(CancellationToken stoppingToken)
{
while(!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Executing Worker at {time}", DateTimeOffset.Now);
await Task.Delay(_timeout, stoppingToken);
}
}
}
Next, wire up the Host Builder in Program.cs. The important part is the call to AddHostedService<Worker> which is what wires up service host to our Worker class.
class Program
{
static void Main(string[] args) =>
CreateHostBuilder(args).Build().Run();
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(configBuilder => configBuilder.AddJsonFile("appsettings.json"))
.UseWindowsService()
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Worker>();
});
}
There are two other optional pieces that I added as examples.
- The call to ConfigureAppConfiguration is used to load config settings from appsettings.json
- The call to .UseWindowsService() - again, if you're not going to host as a Windows Service, then that call can be removed.
And that's all there is to it! Of course, you can add in other extensions supported by the Hosting API's, e.g. other types of configuration providers, secrets, different logging etc.