C# HttpClientでKeep-Aliveを無効にする

仕事で利用していたクラウドサービスのAPIの仕様で、リクエスト都度で認証する必要があり、ハマったので備忘録にしておきます。

当初は以下のようにHttpClientでAPIをコールしていたのですが、一度認証されるとそのセッションが使いまわされてしまいます。
HttpClientをDisposeすることでもコネクションを破棄することもできるのですが、それはそれでソケットの枯渇という別の問題も生みます。

開発者を苦しめる.NETのHttpClientのバグと紛らわしいドキュメント

// HttpClientインスタンスはstatic変数として使いまわす
private static HttpClient httpClient = new HttpClient()

// リクエスト生成
var request = new HttpRequestMessage
{
    Method = HttpMethod.Post,
    RequestUri = new Uri("http://ohke.hateblo.jp/")
};

// Basic認証ヘッダを付与する
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(
    "Basic",
    Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("{0}:{1}", userName, userPassword))));

// リクエストの送信
var response = await httpClient.SendAsync(request);

リクエスト都度認証させるためにはKeep-Aliveを無効にして、HTTPのConnectionヘッダをCloseにする必要があります(これに気付かされるのも時間がかかったのですが)。

HttpWebRequestにはKeepAliveプロパティをfalseにすれば良いのですが、HttpClientを使う場合はHttpRequestMessageのHeadersプロパティ(またはHttpClientのDefaultRequestHeaders)に直接書き加える必要があります。

これでリクエストヘッダがConnection: Closeとなり、Keep-Aliveが無効になります。

// Basic認証ヘッダを付与する
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(
    "Basic",
    Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("{0}:{1}", userName, userPassword))));

// Keep-Aliveをオフにする(リクエスト都度認証させる)
request.Headers.Add("Connection", "close");

// リクエストの送信
var response = await httpClient.SendAsync(request);

通常は一度認証したセッションは使いまわすべきなので、レアケースかとは思います。