ASP.Net CoreでHttpClientクラスを最適に使用する方法を理解しようとしています。ASP.NetコアでHTTPClientをDIシングルトンとして使用する最良の方法
ドキュメントおよびいくつかの記事によれば、クラスはアプリケーションの存続期間中一度だけインスタンス化され、複数の要求に対して共有されます。残念ながら、私はコアでこれを正しく行う方法の例を見つけることができませんでしたので、私は以下の解決策を考案しました。
私は、2つの異なるエンドポイント(ビジネスロジックとAPI駆動型ImageServer用のAPIServerを使用しています)を使用する必要があるので、私はアプリケーションで使用できる2つのHttpClientシングルトンを持つことを考えています。次のように私はappsettings.jsonで私servicepointsを構成した
:
"ServicePoints": {
"APIServer": "http://localhost:5001",
"ImageServer": "http://localhost:5002",
}
次へ]を、私は私の2 httpclientsをインスタンス化し、静的辞書でそれらを保持するHttpClientsFactoryを作成しました。
public class HttpClientsFactory : IHttpClientsFactory
{
public static Dictionary<string, HttpClient> HttpClients { get; set; }
private readonly ILogger _logger;
private readonly IOptions<ServerOptions> _serverOptionsAccessor;
public HttpClientsFactory(ILoggerFactory loggerFactory, IOptions<ServerOptions> serverOptionsAccessor) {
_logger = loggerFactory.CreateLogger<HttpClientsFactory>();
_serverOptionsAccessor = serverOptionsAccessor;
HttpClients = new Dictionary<string, HttpClient>();
Initialize();
}
private void Initialize()
{
HttpClient client = new HttpClient();
// ADD imageServer
var imageServer = _serverOptionsAccessor.Value.ImageServer;
client.BaseAddress = new Uri(imageServer);
HttpClients.Add("imageServer", client);
// ADD apiServer
var apiServer = _serverOptionsAccessor.Value.APIServer;
client.BaseAddress = new Uri(apiServer);
HttpClients.Add("apiServer", client);
}
public Dictionary<string, HttpClient> Clients()
{
return HttpClients;
}
public HttpClient Client(string key)
{
return Clients()[key];
}
}
次に、DIを定義するときに使用できるインターフェイスを作成しました。 HttpClientsFactoryクラスはこのインターフェイスを継承しています。
public interface IHttpClientsFactory
{
Dictionary<string, HttpClient> Clients();
HttpClient Client(string key);
}
これを、ConfigureServicesメソッドのStartupクラスの次のように、私のDependencyコンテナに挿入する準備が整いました。
// Add httpClient service
services.AddSingleton<IHttpClientsFactory, HttpClientsFactory>();
これはすべてコントローラで使用するように設定されています。
まず、私は依存関係を取ります。これを行うために、私はそれを保持するプライベートクラスプロパティを作成し、それをコンストラクタシグネチャに追加し、着信オブジェクトをローカルクラスプロパティに割り当てることで終了します。
private IHttpClientsFactory _httpClientsFactory;
public AppUsersAdminController(IHttpClientsFactory httpClientsFactory)
{
_httpClientsFactory = httpClientsFactory;
}
最後に、ファクトリを使用してhtppclientを要求し、コールを実行できるようになりました。以下、私がhttpclientsfactoryを使用してイメージサーバからイメージを要求する例を示します。
[HttpGet]
public async Task<ActionResult> GetUserPicture(string imgName)
{
// get imageserver uri
var imageServer = _optionsAccessor.Value.ImageServer;
// create path to requested image
var path = imageServer + "/imageuploads/" + imgName;
var client = _httpClientsFactory.Client("imageServer");
byte[] image = await client.GetByteArrayAsync(path);
return base.File(image, "image/jpeg");
}
完了!
私はこれをテストして、私の開発環境でうまく動作します。しかし、これを実装する最良の方法であるかどうかはわかりません。私は次の質問を残します:
- このソリューションはスレッドセーフですか? (MS doc: 'このタイプのpublic static(Visual Basic Basicで共有されている)メンバーはスレッドセーフです。')
- この設定では、多くの個別の接続を開かずに負荷を処理できますか?
- 'Singleton HttpClient?'で説明されているDNSの問題を処理するASP.Netコアで何をすればよいですか?この重大な行動や修正方法に注意してください。」http://byterot.blogspot.be/2016/07/singleton-httpclient-dns.html
- 他の改善や提案はありますか?
興味深いアプローチをアップロードするユーザーを扱う
APIは、私はサービスとしてHTTPClientの静的メソッドを持っているが、私はへこみファクトリパターンを考えます。私は認証を必要とするAPIの下でこれを試してみるべきか、あるいはあなたのAPIのケースがOpen APIであるのだろうと思っていましたか?異なるトークンを必要とするさまざまな要求に対して、これをどのように処理しますか? –
@MuqeetKhanあなたの質問に対する私の答えは、もうちょっと待ってから予想していました。だから、下の例を見てください。 – Laobu
2つの 'HttpClient'インスタンスは必要ありません。ただ1つのシングルトンを登録して使用してください。 DNSの問題は引き続き存在します。 sidenoteとして、 'Factory'クラス**はオブジェクトインスタンスを作成します**。 Factoryパターン[here](https://msdn.microsoft.com/en-us/library/ee817667.aspx)の詳細を参照してください。 – gldraphael