web-dev-qa-db-fra.com

Moyen approprié d’enregistrer HostedService dans ASP.NET Core. AddHostedService vs AddSingleton

Quel est le moyen approprié d’enregistrer un service hébergé personnalisé dans ASP.NET Core 2.1? Par exemple, j'ai un service hébergé personnalisé dérivé de BackgroundService nommé MyHostedService. Comment dois-je l'enregistrer?

public IServiceProvider ConfigureServices(IServiceCollection services)
{           
    //...
    services.AddSingleton<IHostedService, MyHostedService>();
}

ou

public IServiceProvider ConfigureServices(IServiceCollection services)
{           
    //...
    services.AddHostedService<MyHostedService>();
}

?

Ici nous pouvons voir le premier cas, mais ici il y a un deuxième cas.

Ces méthodes sont-elles égales?

19
Denis Babarykin

Ils sont similaires mais pas complètement

AddHostedService fait partie de Microsoft.Extensions.Hosting.Abstractions.

Il appartient à Microsoft.Extensions.Hosting.Abstractions dans la classe ServiceCollectionHostedServiceExtensions

using Microsoft.Extensions.Hosting;

namespace Microsoft.Extensions.DependencyInjection
{
    public static class ServiceCollectionHostedServiceExtensions
    {
        /// <summary>
        /// Add an <see cref="IHostedService"/> registration for the given type.
        /// </summary>
        /// <typeparam name="THostedService">An <see cref="IHostedService"/> to register.</typeparam>
        /// <param name="services">The <see cref="IServiceCollection"/> to register with.</param>
        /// <returns>The original <see cref="IServiceCollection"/>.</returns>
        public static IServiceCollection AddHostedService<THostedService>(this IServiceCollection services)
            where THostedService : class, IHostedService
            => services.AddTransient<IHostedService, THostedService>();
    }
}

Notez qu'il utilise Transient étendue de la durée de vie et non Singleton

En interne, le framework ajoute tous les services hébergés à un autre service (HostedServiceExecutor)

public HostedServiceExecutor(ILogger<HostedServiceExecutor> logger, 
    IEnumerable<IHostedService> services) //<<-- note services collection
{
    _logger = logger;
    _services = services;
}

au démarrage, il s'agit d'un singleton via le WebHost Constructor .

_applicationServiceCollection.AddSingleton<HostedServiceExecutor>();
6
Nkosi

Utilisez AddHostedService

Un service hébergé est plus qu'un simple service. Le moteur d'exécution "le sait", peut lui dire de commencer en appelant StartAsync ou de s'arrêter en appelant StopAsync() à chaque fois que le pool d'applications est recyclé. Le moteur d'exécution peut attendre que le service hébergé se termine avant que l'application Web elle-même se termine.

Comme la documentation explique , un service limité peut être utilisé en créant une étendue dans la méthode de travail du service hébergé. Il en va de même pour les services transitoires.

Pour ce faire, un IServicesProvider ou un IServiceScopeFactory doit être injecté dans le constructeur du service hébergé et utilisé pour créer l'étendue.

Empruntant à la documentation, le constructeur et la méthode de travail du service peuvent ressembler à ceci:

public IServiceProvider Services { get; }

public ConsumeScopedServiceHostedService(IServiceProvider services, 
    ILogger<ConsumeScopedServiceHostedService> logger)
{
    Services = services;
    _logger = logger;
}


private void DoWork()
{
    using (var scope = Services.CreateScope())
    {
        var scopedProcessingService = 
            scope.ServiceProvider
                .GetRequiredService<IScopedProcessingService>();

        scopedProcessingService.DoWork();
    }
}

Cette question connexe montre comment utiliser un DbContext transitoire dans un service hébergé:

public class MyHostedService : IHostedService
{
    private readonly IServiceScopeFactory scopeFactory;

    public MyHostedService(IServiceScopeFactory scopeFactory)
    {
        this.scopeFactory = scopeFactory;
    }

    public void DoWork()
    {
        using (var scope = scopeFactory.CreateScope())
        {
            var dbContext = scope.ServiceProvider.GetRequiredService<MyDbContext>();
            …
        }
    }
    …
}
17
Panagiotis Kanavos