Working on a BackgroundService
that is published to Azure as a Web Job, I noticed something strange (works fine on Azure, exception when running locally), so I tried to recreate the situation.
Program.cs
:
using TestBackgroundJob;
IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddScoped<IDummyService, DummyService>();
services.AddHostedService<Worker>();
})
.Build();
await host.RunAsync();
Worker
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
private readonly IDummyService _dummyService;
public Worker(ILogger<Worker> logger, IDummyService dummyService)
{
_logger = logger;
_dummyService = dummyService;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
await Task.Delay(1000, stoppingToken);
}
}
}
Of course that when I run this local I get an exception, because I try to inject a scoped service inside Worker
class, that being a HostedService
, is singleton:
Cannot consume scoped service 'TestBackgroundJob.IDummyService' from singleton 'Microsoft.Extensions.Hosting.IHostedService'.)'
However if I publish this as a Web Job on Azure, the code works fine. I could not found any articles that explain this. Looks like when running on Azure, the scope of Worker
class is changed from singleton to scoped. Is that what really happen?
The Worker always has Singleton
lifetime and won't change.
But let's see what happens when you want to create a default host (CreateDefaultBuilder
method):
Default builder settings
The CreateDefaultBuilder method:
As you can see the scope validation only happens in the Development (local) mode but when you publish it on Azure it will run in the Production mode.
So why it's important to take care about not resolving Scope service to Singleton?
It's all about using resources since when you use the Scope service in the Singleton then it will behave like a singleton and stay alive on the application lifetime!
It is recommended to use IServiceScopeFactory
for solving your issue.
For reading more about Generic Host in .net, here is the place:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-7.0