IHostedService - problém se závislostí služeb typu 'Scoped'

Hosted služby slouží pro zpracovávání dlouhotrvajících úloh na pozadí kontextu aplikace.

Pro vytvoření hosted service je potřeba, aby třída dědila z IHostedService, nebo přímo z BackgroundService. Poté třídu zaregistrujeme jako hosted service:

services.AddHostedService<T>();

Problém

Do hosted služby občas potřebujeme závislosti služeb, které mají registrovaný životní cyklus jako Scoped. Hosted služba nevytváří vlastní scope (je registrovaná jako singleton), a tím pádem služby zaregistrované jako Scoped budou vyhazovat exception typu:

System.InvalidOperationException: ‘Cannot consume scoped service ‘Service’ from singleton ‘Microsoft.Extensions.Hosting.IHostedService’.

Řešení

Pro použítí závislostí služeb typu Scoped si musíme vytvořit vlastní scope pomocí IServiceScopeFactory, kde si službu vytáhneme přes - GetRequiredService< T>()

Ukázka

public class DefaultHostedService : IHostedService
{
    private readonly IServiceScopeFactory _serviceScopeFactory;

    public DefaultHostedService(IServiceScopeFactory serviceScopeFactory)
    {
        this._serviceScopeFactory = serviceScopeFactory;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        using (var scope = _serviceScopeFactory.CreateScope())
        {
            var service = scope.ServiceProvider.GetRequiredService<IService>();
            //logic
        }
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }
}
Written on July 17, 2019