web-dev-qa-db-ja.com

異なる認証ヘッダーを持つHttpClient単一インスタンス

.net HttpClientは再利用を念頭に置いて設計されており、短命のインスタンスでは long lived および memory leaksが報告されている になることを意図していることを考えると複数のユーザーのエンドポイントを呼び出すときに、異なるベアラートークン(または任意の認証ヘッダー)を使用して特定のエンドポイントに安らぎの呼び出しを行う場合、どのガイドラインがありますか?

private void CallEndpoint(string resourceId, string bearerToken) {
  httpClient.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("bearer", bearerToken);
  var response = await httpClient.GetAsync($"resource/{resourceid}");
}

上記のコードがWebアプリケーションの任意の数のスレッドによって呼び出される可能性があるため、最初の行のヘッダーセットがリソースの呼び出し時に使用されるものと異なる可能性があります。

ロックを使用して競合を引き起こさず、ステートレスWebアプリケーションを維持することなく、単一のエンドポイントのHttpClientを作成および破棄するための推奨されるアプローチは何ですか(私の現在のプラクティスは、エンドポイントごとに単一のクライアントを作成することです)?


ライフサイクル

HttpClientはIDisposableインターフェイスを間接的に実装しますが、HttpClientの推奨される使用法は、リクエストごとに破棄することではありません。 HttpClientオブジェクトは、アプリケーションがHTTP要求を行う必要がある限り存続することを目的としています。オブジェクトが複数のリクエストにまたがって存在すると、DefaultRequestHeadersを設定する場所が有効になり、HttpWebRequestで必要であったように、リクエストごとにCredentialCacheやCookieContainerなどを再指定する必要がなくなります。

59
Bronumski

ヘッダーが通常同じになる場合は、DefaultRequestHeadersを設定できます。ただし、ヘッダーを指定するためにそのプロパティを使用する必要はありません。あなたが決定したように、同じクライアントを使用して複数のスレッドを持っている場合、それはうまくいきません。 1つのスレッドで行われたデフォルトヘッダーの変更は、他のスレッドで送信された要求に影響を与えます。

クライアントにデフォルトのヘッダーを設定して各リクエストに適用できますが、ヘッダーは実際にはリクエストのプロパティです。そのため、ヘッダーがリクエストに固有の場合、リクエストに追加するだけです。

request.Headers.Authorization = new AuthenticationHeaderValue("bearer", bearerToken);

つまり、HttpRequestの作成を伴わない単純化されたメソッドは使用できません。使用する必要があります

public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request)

文書化された ここ

GETおよびPOSTのメソッドは、送信される前にリクエストヘッダーなどのHttpRequestMessageを操作できる拡張メソッドを介して行われます。

public static Task<HttpResponseMessage> GetAsync
    (this HttpClient httpClient, string uri, Action<HttpRequestMessage> preAction)
{
    var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, uri);

    preAction(httpRequestMessage);

    return httpClient.SendAsync(httpRequestMessage);
}

public static Task<HttpResponseMessage> PostAsJsonAsync<T>
    (this HttpClient httpClient, string uri, T value, Action<HttpRequestMessage> preAction)
{
    var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, uri)
    {
        Content = new ObjectContent<T>
            (value, new JsonMediaTypeFormatter(), (MediaTypeHeaderValue)null)
    };
    preAction(httpRequestMessage);

    return httpClient.SendAsync(httpRequestMessage);
}

これらは、次のように使用できます。

var response = await httpClient.GetAsync("token",
    x => x.Headers.Authorization = new AuthenticationHeaderValue("basic", clientSecret));
63
Scott Hannen