I have the following successfully working in .NET Core 2, but it doesn't work in .NET Core 3.
I've made a new Worker Service .Net Core 3 project from scratch and added only the minimum to recreate my error.
Here is my entry point in Program.cs
namespace WorkerService1DeleteMe
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.Configure<ConfigChunk>(hostContext.Configuration.GetSection("ConfigChunk"));
services.AddHostedService<Worker>();
});
}
public class ConfigChunk
{
public string Server { get; set; }
}
}
So there is a single line added to CreateHostBuilder
here, to the Configure
method, and a new ConfigChunk
class at the bottom, to match the schema of a section in appsettings.json.
Finally, an extension of the parameters to the Worker constructor to let it consume the SettingsChunk:
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
private readonly ConfigChunk _config;
public Worker(ILogger<Worker> logger, ConfigChunk config)
{
_logger = logger;
_config = config;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
await Task.Delay(1000, stoppingToken);
}
}
}
As alluded to, this works fine in NET Core 2, but in 3 it fails with:
Unable to resolve service for type 'WorkerService1DeleteMe.ConfigChunk' while attempting to activate 'WorkerService1DeleteMe.Worker'.
I feel like I am missing something blindingly obvious but must confess I am at a loss. What I have observed is that I can make the whole thing work by going services.AddSingleton
instead of services.Configure
but I much prefer the pattern and reload functionality of the Configure approach if I can make it work.
Few options are available.
With current configuration update worker to use IOptions<TOptions>
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
private readonly ConfigChunk _config;
public Worker(ILogger<Worker> logger, IOptions<ConfigChunk> config) {
_logger = logger;
_config = config.Value;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
while (!stoppingToken.IsCancellationRequested) {
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
await Task.Delay(1000, stoppingToken);
}
}
}
Or leave the worker as is and update the configuration to allow the class itself to be injected.
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) => {
services.Configure<ConfigChunk>(hostContext.Configuration.GetSection("ConfigChunk"));
services.AddHostedService<Worker>();
services.AddTransient<ConfigChunk>(_ => _.GetRequiredService<IOptions<ConfigChunk>>().Value);
});
The second example will allow for explicit injection of the ConfigChunk
while still allowing the options features to be in effect and does not tightly couple the worker to framework concerns.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With