Правильный способ регистрации 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()
в другой класс.