web-dev-qa-db-ja.com

C#共有HttpClientを使用してCookieを渡す方法

私は次の設定をしています:

JSクライアント-> Web Api-> Web Api

認証Cookieを最後まで送信する必要があります。私の問題は、あるWebAPIから別のWebAPIに送信することです。 FormsAuthenticationを使用する古いシステムと統合されているため、認証Cookieを渡す必要があります。

パフォーマンス上の理由から、次の辞書でHttpClientのリスト(Web APIごとに1つ)を共有します。

private static ConcurrentDictionary<ApiIdentifier, HttpClient> _clients = new ConcurrentDictionary<ApiIdentifier, HttpClient>();

したがって、識別子が与えられると、対応するHttpClientを取得できます。

以下は機能しますが、これは悪いコードであると確信しています。

HttpClient client = _clients[identifier];
var callerRequest = HttpContext.Current.Items["MS_HttpRequestMessage"] as HttpRequestMessage;
string authCookieValue = GetAuthCookieValue(callerRequest);

if (authCookieValue != null)
{
    client.DefaultRequestHeaders.Remove("Cookie");
    client.DefaultRequestHeaders.Add("Cookie", ".ASPXAUTH=" + authCookieValue);
}

HttpResponseMessage response = await client.PutAsJsonAsync(methodName, dataToSend);

// Handle response...

これの何が問題なのかというと、1)リクエストでDefaultRequestHeadersを操作するのは間違っているように見え、2)HttpClientが共有されているため、2つの同時リクエストがCookieを台無しにする可能性があります。

一致する問題のほとんどがすべてのリクエストに対してHttpClientをインスタンス化するため、解決策を見つけることなくしばらく探していました。したがって、必要なヘッダーを設定できますが、これは避けようとしています。

ある時点で、HttpResponseMessageを使用してリクエストが機能するようになりました。おそらく、それは解決策へのインスピレーションになる可能性があります。

だから私の質問は:HttpClientを使用して単一のリクエストにCookieを設定する方法はありますか?それは同じインスタンスを使用する他のクライアントから安全になりますか?

8
Casper

PutAsJsonAsync()を呼び出す代わりに、HttpRequestMessageとSendAsync()を使用できます。

Uri requestUri = ...;
HttpMethod method = HttpMethod.Get /*Put, Post, Delete, etc.*/;
var request = new HttpRequestMessage(method, requestUri);
request.Headers.TryAddWithoutValidation("Cookie", ".ASPXAUTH=" + authCookieValue);
request.Content = new StringContent(jsonDataToSend, Encoding.UTF8, "application/json");
var response = await client.SendAsync(request);

更新:HTTPクライアントが応答からのCookieを保存しないようにするには、次のようにする必要があります。

var httpClient = new HttpClient(new HttpClientHandler() { UseCookies = false; });

そうしないと、1つのクライアントを使用し、他のCookieを共有することにより、予期しない動作が発生する可能性があります。

16
Serge Semenov