web-dev-qa-db-ja.com

ASP.NET Coreで依存性注入を介してIHostedServiceへの参照を取得するにはどうすればよいですか?

細部

ASP.NET 2.1で推奨されるIHostedServiceインターフェイスを使用してバックグラウンド処理構造を作成しようとしました。次のようにサービスを登録します。

services.AddSingleton<AbstractProcessQueue<AbstractImportProcess>>();
services.AddHostedService<AbstractBackgroundProcessService<AbstractImportProcess>>();

services.AddSignalR();

AbstractProcessQueueは、エンキューおよびデキューできるプロセスのBlockingCollectionの単なるラッパーです。 AbstractBackgroundProcessServiceIHostedServiceインターフェイスを実装し、開始できる新しいプロセスのキューを調べます。

SignalRハブ内で、Dependency Injectionメカニズムを介してバックグラウンド処理サービスへの参照を取得しようとすると、問題が発生します。次の解決策を試しましたが、意図したとおりに機能していないようです。

オプション1:

public HubImportClient(IServiceProvider provider)
{
    //This returns null.
    var service = provider.GetService<AbstractBackgroundProcessService<AbstractImportProcess>>();
}

オプション2:

public HubImportClient(IServiceProvider provider)
{
    //This returns null.
    var service = (AbstractBackgroundProcessService<AbstractImportProcess>) provider.GetService(typeof(AbstractBackgroundProcessService<AbstractImportProcess>>));
}

オプション3:

public HubImportClient(IServiceProvider provider)
{
    //This throws an exception, because the service is missing.
    var service = provider.GetRequiredService<AbstractBackgroundProcessService<AbstractImportProcess>>();
}

オプション4:

public HubImportClient(IServiceProvider provider)
{
    //This throws an exception, because the service is missing.
    var service = (AbstractBackgroundProcessService<AbstractImportProcess>) provider.GetRequiredService(typeof(AbstractBackgroundProcessService<AbstractImportProcess>);
}

オプション5:

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

オプション6:

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

オプション7:

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

オプション8:

//This works, but prevents multiple implementations again.
public HubImportClient(IHostedService service)
{
    this.Service = service;   
}

オプション9:

//This does not work again.
public HubImportClient(AbstractBackgroundProcessService<AbstractImportProcess> service)
{
    this.Service = service;   
}

質問

それで私の質問は残っています:IHostedService実装への参照を取得するにはどうすればよいですか?

(a):タイプパラメータのみが異なるサービスの複数のインスタンスを注入できます(例:AbstractImportProcessesのホスティングサービスとAbstractExportProcessesのホスティングサービス)

(b):その特定の型パラメーターのIHostedServiceのインスタンスは1つしかありません。

助けてくれてありがとう!

12
Teun Kooijman

このトピックに関していくつかの議論がありました。たとえば、 https://github.com/aspnet/Hosting/issues/1489 を参照してください。遭遇する問題の1つは、ホストされたサービスが一時的なサービスとして(ASP.NET Core 2.1以降から)追加されることです。つまり、依存関係の注入コンテナーからホストされたサービスを解決すると、毎回新しいインスタンスが発生します。

一般的なアドバイスは、他のサービスと共有またはやり取りするビジネスロジックを特定のサービスにカプセル化することです。コードを見て、AbstractProcessQueue<AbstractImportProcess>クラスにビジネスロジックを実装し、ビジネスロジックの実行をAbstractBackgroundProcessService<T>の唯一の関心事にすることをお勧めします。

6
Henk Mollema