Правильный способ регистрации HostedService в ASP.NET Core. AddHostedService против AddSingleton

Как правильно зарегистрировать пользовательский сервис в ASP.NET Core 2.1? Например, у меня есть пользовательский сервис, полученный из BackgroundService с именем MyHostedService, Как мне это зарегистрировать?

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

или же

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

?

Здесь мы можем видеть первый случай, но здесь есть второй случай.

Равны ли эти методы?

3 ответа

Использование AddHostedService

Хостинг-сервис - это больше, чем просто сервис Singleton. Среда выполнения "знает" об этом, может сказать, что нужно начать с вызова StartAsync или остановитесь по телефону StopAsync() например, когда пул приложений перерабатывается. Среда выполнения может ожидать завершения работы размещенной службы, прежде чем само веб-приложение завершит работу.

Как объясняется в документации, сервис с областью действия можно использовать, создав область внутри рабочего метода размещенной службы. То же самое относится и к временным услугам.

Для этого IServicesProvider или IServiceScopeFactory должны быть внедрены в конструктор размещенной службы и использованы для создания области.

Заимствуя из документов, конструктор сервиса и метод работника могут выглядеть так:

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

Этот связанный вопрос показывает, как использовать временный DbContext в размещенной службе:

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

Они похожи, но не полностью

AddHostedService это часть Microsoft.Extensions.Hosting.Abstractions,

Это принадлежит Microsoft.Extensions.Hosting.Abstractions в 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>();
    }
}

Обратите внимание, что он использует Transient продолжительность жизни, а не Singleton

Внутренне фреймворк добавляет все размещенные сервисы в другой сервис ( HostedServiceExecutor )

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

при запуске это одиночка через конструктор WebHost.

_applicationServiceCollection.AddSingleton<HostedServiceExecutor>();

Одна огромная разница в том, что ленив, а нетерпелив.

Услуга добавлена ​​сAddSingleton()будет создан при первом внедрении в конструктор класса. Это нормально для большинства служб, но если вам действительно нужна фоновая служба, вы, вероятно, захотите, чтобы она запускалась сразу.

Служба, добавленная с помощью, будет немедленно создана, даже если ни один другой класс никогда не захочет, чтобы она была внедрена в его конструктор. Это типично для фоновых служб, которые работают постоянно.

Кроме того, кажется, что вы не можете внедрить службу, добавленную с помощьюAddHostedService()в другой класс.

Другие вопросы по тегам