ASP.NET 2.1で推奨されるIHostedService
インターフェイスを使用してバックグラウンド処理構造を作成しようとしました。次のようにサービスを登録します。
services.AddSingleton<AbstractProcessQueue<AbstractImportProcess>>();
services.AddHostedService<AbstractBackgroundProcessService<AbstractImportProcess>>();
services.AddSignalR();
AbstractProcessQueue
は、エンキューおよびデキューできるプロセスのBlockingCollection
の単なるラッパーです。 AbstractBackgroundProcessService
はIHostedService
インターフェイスを実装し、開始できる新しいプロセスのキューを調べます。
SignalR
ハブ内で、Dependency Injection
メカニズムを介してバックグラウンド処理サービスへの参照を取得しようとすると、問題が発生します。次の解決策を試しましたが、意図したとおりに機能していないようです。
public HubImportClient(IServiceProvider provider)
{
//This returns null.
var service = provider.GetService<AbstractBackgroundProcessService<AbstractImportProcess>>();
}
public HubImportClient(IServiceProvider provider)
{
//This returns null.
var service = (AbstractBackgroundProcessService<AbstractImportProcess>) provider.GetService(typeof(AbstractBackgroundProcessService<AbstractImportProcess>>));
}
public HubImportClient(IServiceProvider provider)
{
//This throws an exception, because the service is missing.
var service = provider.GetRequiredService<AbstractBackgroundProcessService<AbstractImportProcess>>();
}
public HubImportClient(IServiceProvider provider)
{
//This throws an exception, because the service is missing.
var service = (AbstractBackgroundProcessService<AbstractImportProcess>) provider.GetRequiredService(typeof(AbstractBackgroundProcessService<AbstractImportProcess>);
}
public HubImportClient(IServiceProvider provider)
{
//This returns a correct service, but prevents me from adding additional AbstractBackgroundProcessService implementations with different type parameters.
//Additionally, it seems like this reference was newly created, and not the instance that was created on application startup (i.e. the hash codes are different, and the constructor is called an additional time).
var service = provider.GetService<IHostedService>();
if(service is AbstractBackgroundProcessService<AbstractProcessService>)
{ this.Service = (AbstractBackgroundProcessService<AbstractProcessService>) service;}
}
public HubImportClient(IServiceProvider provider)
{
//This works similarly to the previous option, and allows multiple implementations, but the constructor is still called twice and the instances thus differ.
AbstractBackgroundProcessService<AbstractImportProcess> service = null;
foreach(IHostedService service in provider.GetServices<IHostedService>())
{
if(service is AbstractBackgroundProcessService<AbstractImportProcess>)
{
service = (AbstractBackgroundProcessService<AbstractImportProcess>) service;
break;
}
}
}
public HubImportClient(IServiceProvider provider)
{
//This just skips the for each loop all together, because no such services could be found.
AbstractBackgroundProcessService<AbstractImportProcess> service = null;
foreach(AbstractBackgroundProcessService<AbstractImportProcess> current in provider.GetServices<AbstractBackgroundProcessService<AbstractImportProcess> >())
{
service = current;
break;
}
}
//This works, but prevents multiple implementations again.
public HubImportClient(IHostedService service)
{
this.Service = service;
}
//This does not work again.
public HubImportClient(AbstractBackgroundProcessService<AbstractImportProcess> service)
{
this.Service = service;
}
それで私の質問は残っています:IHostedService
実装への参照を取得するにはどうすればよいですか?
(a):タイプパラメータのみが異なるサービスの複数のインスタンスを注入できます(例:AbstractImportProcess
esのホスティングサービスとAbstractExportProcess
esのホスティングサービス)
(b):その特定の型パラメーターのIHostedService
のインスタンスは1つしかありません。
助けてくれてありがとう!
このトピックに関していくつかの議論がありました。たとえば、 https://github.com/aspnet/Hosting/issues/1489 を参照してください。遭遇する問題の1つは、ホストされたサービスが一時的なサービスとして(ASP.NET Core 2.1以降から)追加されることです。つまり、依存関係の注入コンテナーからホストされたサービスを解決すると、毎回新しいインスタンスが発生します。
一般的なアドバイスは、他のサービスと共有またはやり取りするビジネスロジックを特定のサービスにカプセル化することです。コードを見て、AbstractProcessQueue<AbstractImportProcess>
クラスにビジネスロジックを実装し、ビジネスロジックの実行をAbstractBackgroundProcessService<T>
の唯一の関心事にすることをお勧めします。