ASP.NET Core 2.1でカスタムホストサービスを登録する適切な方法は何ですか?たとえば、 BackgroundService named MyHostedService
から派生したカスタムホストサービスがあります。どうすれば登録できますか?
public IServiceProvider ConfigureServices(IServiceCollection services)
{
//...
services.AddSingleton<IHostedService, MyHostedService>();
}
または
public IServiceProvider ConfigureServices(IServiceCollection services)
{
//...
services.AddHostedService<MyHostedService>();
}
?
ここ 最初のケースを見ることができますが、 ここ 2番目のケースがあります。
これらの方法は同等ですか?
それらは似ていますが、完全ではありません
AddHostedService
はMicrosoft.Extensions.Hosting.Abstractions
の一部です。
ServiceCollectionHostedServiceExtensions
クラスのMicrosoft.Extensions.Hosting.Abstractions
に属します
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 Constructor を介したシングルトンです。
_applicationServiceCollection.AddSingleton<HostedServiceExecutor>();
AddHostedService
を使用
ホスト型サービスは、単なるシングルトンサービスではありません。ランタイムはそれを「認識」し、StartAsync
を呼び出すことで開始するように、またはアプリケーションプールがリサイクルされるたびにStopAsync()
を呼び出すことで停止するように指示できます。ランタイムは、Webサービス自体が終了する前に、ホストされたサービスが終了するのを待つことができます。
ドキュメントで説明 スコープサービスcanは、ホストされたサービスのワーカーメソッド内にスコープを作成することで消費されます。同じことが一時的なサービスにも当てはまります。
これを行うには、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>();
…
}
}
…
}