ASP.NETコア2のWeb APIでは、私は、注入する依存性注入を使用したいhttpClientA
のインスタンスHttpClient
にControllerA
、インスタンスhttpClientB
のHttpClient
へControllerB
。
DI登録コードは次のようになります。
HttpClient httpClientA = new HttpClient();
httpClientA.BaseAddress = endPointA;
services.AddSingleton<HttpClient>(httpClientA);
HttpClient httpClientB = new HttpClient();
httpClientB.BaseAddress = endPointB;
services.AddSingleton<HttpClient>(httpClientB);
サブクラス化HttpClient
してコントローラーごとに一意の型を作成できることはわかっていますが、それはあまり拡張性がありません。
より良い方法は何ですか?
更新特にHttpClientに関してMicrosoftは作業中に何かを持っているようです
https://github.com/aspnet/HttpClientFactory/blob/dev/samples/HttpClientFactorySample/Program.cs#L32-これを指摘してくれた@ mountain-traveller(Dylan)に感謝します。
注:この回答では例として
HttpClient
とを使用してHttpClientFactory
いますが、他の種類のものにも簡単に適用できます。特に新しいを使用してから、好ましいです。HttpClient
IHttpClientFactory
Microsoft.Extensions.Http
組み込みの依存性注入コンテナは名前付き依存性登録をサポートしておらず、現時点ではこれを追加する予定はありません。
この理由の1つは、依存性注入では、必要な名前付きインスタンスの種類を指定するためのタイプセーフな方法がないことです。コンストラクターのパラメーター属性(またはプロパティインジェクションのプロパティの属性)のようなものを使用することは確かにできますが、それはおそらく価値がない別の種類の複雑さです。そしてそれは確かに型システムによって支えられないでしょう、それは依存性注入がどのように機能するかの重要な部分です。
一般に、名前付きの依存関係は、依存関係を適切に設計していないことを示しています。同じタイプの2つの異なる依存関係がある場合、これはそれらが交換可能に使用される可能性があることを意味するはずです。それが当てはまらず、一方が有効で他方が無効である場合、それはあなたがリスコフの置換原則に違反している可能性があることを示しています。
さらに、名前付きの依存関係をサポートする依存性注入に含まれるものを見ると、これらの依存性を取得する唯一の方法は、依存性注入を使用せず、代わりにサービスロケーターパターンを使用することです。これは、DIが促進する制御の反転とは正反対です。。
より大きな依存性注入コンテナの1つであるSimpleInjectorは、次のような名前付き依存性がないことを説明しています。
キーによるインスタンスの解決は、アプリケーションがDIコンテナー自体に多数の依存関係を持つ傾向がある設計に必ずつながるため、SimpleInjectorから意図的に除外されている機能です。キー付きインスタンスを解決するには、Containerインスタンスを直接呼び出す必要があります。これにより、ServiceLocatorのアンチパターンが発生します。
これは、キーによるインスタンスの解決が決して役に立たないという意味ではありません。キーによるインスタンスの解決は、通常、コンテナではなく特定のファクトリのジョブです。このアプローチにより、設計がはるかにクリーンになり、DIライブラリに多数の依存関係をとる必要がなくなり、DIコンテナの作成者が単に考慮しなかった多くのシナリオが可能になります。
とはいえ、このようなものが本当に必要な場合があり、多数のサブタイプと個別の登録を行うことは、単に実現可能ではありません。その場合でも、これにアプローチする適切な方法があります。
ASP.NET Coreのフレームワークコードにこれに似たものがあると私が考えることができる特定の状況が1つあります。それは、認証フレームワークの名前付き構成オプションです。概念をすばやく説明しようと思います(我慢してください):
ASP.NET Coreの認証スタックは、同じタイプの複数の認証プロバイダーの登録をサポートしています。たとえば、アプリケーションが使用する可能性のある複数のOpenIDConnectプロバイダーが存在する可能性があります。しかし、それらはすべてプロトコルの同じ技術的実装を共有していますが、それらが独立して機能し、インスタンスを個別に構成する方法が必要です。
これは、各「認証スキーム」に一意の名前を付けることで解決されます。スキームを追加するときは、基本的に新しい名前を登録し、どのハンドラータイプを使用するかを登録に指示します。さらに、各スキームを構成します。IConfigureNamedOptions<T>
これを使用して実装すると、基本的に未構成のオプションオブジェクトが渡され、名前が一致した場合に構成されます。したがって、認証タイプごとにT
、最終的には複数の登録IConfigureNamedOptions<T>
があり、スキームの個々のオプションオブジェクトを構成できます。
ある時点で、特定のスキームの認証ハンドラーが実行され、実際に構成されたオプションオブジェクトが必要になります。このため、IOptionsFactory<T>
どのデフォルト実装が具体的なオプションオブジェクトを作成する機能を提供するかによって異なりIConfigureNamedOptions<T>
ます。このオブジェクトは、これらすべてのハンドラーによって構成されます。
そして、オプションファクトリのその正確なロジックは、一種の「名前付き依存関係」を実現するために利用できるものです。特定の例に翻訳すると、たとえば次のようになります。
// container type to hold the client and give it a name
public class NamedHttpClient
{
public string Name { get; private set; }
public HttpClient Client { get; private set; }
public NamedHttpClient (string name, HttpClient client)
{
Name = name;
Client = client;
}
}
// factory to retrieve the named clients
public class HttpClientFactory
{
private readonly IDictionary<string, HttpClient> _clients;
public HttpClientFactory(IEnumerable<NamedHttpClient> clients)
{
_clients = clients.ToDictionary(n => n.Key, n => n.Value);
}
public HttpClient GetClient(string name)
{
if (_clients.TryGet(name, out var client))
return client;
// handle error
throw new ArgumentException(nameof(name));
}
}
// register those named clients
services.AddSingleton<NamedHttpClient>(new NamedHttpClient("A", httpClientA));
services.AddSingleton<NamedHttpClient>(new NamedHttpClient("B", httpClientB));
次に、HttpClientFactory
どこかに挿入し、そのGetClient
メソッドを使用して名前付きクライアントを取得します。
明らかに、この実装と私が以前に書いたことについて考えると、これはサービスロケーターパターンに非常に似ています。ある意味では、既存の依存性注入コンテナの上に構築されていますが、この場合は実際には1つです。これはそれをより良くしますか?おそらくそうではありませんが、それは既存のコンテナで要件を実装する方法なので、それが重要です。完全な防御のために、上記の認証オプションの場合、オプションファクトリは実際のファクトリであるため、実際のオブジェクトを構築し、既存の事前登録されたインスタンスを使用しないため、技術的にはサービスロケーションパターンではありません。
明らかに、他の選択肢は、上記で書いたことを完全に無視し、ASP.NETCoreで別の依存性注入コンテナーを使用することです。たとえば、Autofacは名前付きの依存関係をサポートしており、ASP.NETCoreの既定のコンテナーを簡単に置き換えることができます。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加