wake-up-neo.com

Richtige Methode zum Registrieren von HostedService in ASP.NET Core. AddHostedService gegen AddSingleton

Wie kann ein benutzerdefinierter gehosteter Dienst in ASP.NET Core 2.1 ordnungsgemäß registriert werden? Zum Beispiel habe ich einen benutzerdefinierten gehosteten Dienst, der von BackgroundService mit dem Namen MyHostedService abgeleitet ist. Wie soll ich es registrieren?

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

oder

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

?

hier wir können den ersten Fall sehen, aber hier es gibt den zweiten Fall.

Sind diese Methoden gleich?

19
Denis Babarykin

Sie sind ähnlich, aber nicht vollständig

AddHostedService ist Teil von Microsoft.Extensions.Hosting.Abstractions.

Es gehört Microsoft.Extensions.Hosting.Abstractions in der Klasse 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>();
    }
}

Beachten Sie, dass der Gültigkeitsbereich Transient und nicht Singleton verwendet wird.

Intern fügt das Framework alle gehosteten Dienste einem anderen Dienst hinzu (HostedServiceExecutor)

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

beim Start ist das ein Singleton über den WebHost Constructor .

_applicationServiceCollection.AddSingleton<HostedServiceExecutor>();
6
Nkosi

Benutze AddHostedService

Ein gehosteter Dienst ist mehr als nur ein Einzeldienst. Die Laufzeit "weiß" davon, kann sie anweisen, durch Aufrufen von StartAsync zu starten oder durch Aufrufen von StopAsync() zu stoppen, wenn z. B. der Anwendungspool wiederverwendet wird. Die Laufzeit kann warten, bis der gehostete Dienst beendet ist, bevor die Webanwendung selbst beendet wird.

Wie in der Dokumentation erläutert kann ein Dienst mit Gültigkeitsbereich verwendet werden , indem ein Bereich innerhalb der Worker-Methode des gehosteten Dienstes erstellt wird. Gleiches gilt für flüchtige Dienste.

Dazu muss ein IServicesProvider oder eine IServiceScopeFactory in den Konstruktor des gehosteten Dienstes eingefügt und zum Erstellen des Bereichs verwendet werden.

Aus den Dokumenten entlehnt, kann die Konstruktor- und Arbeitermethode des Dienstes folgendermaßen aussehen:

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();
    }
}

Diese verwandte Frage zeigt, wie ein vorübergehender DbContext in einem gehosteten Dienst verwendet wird:

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