C Sharpとネットワーク - HttpClient
概要
HttpClientクラスは、HTTPリクエストを投げる場合に使用するクラスである。
.NET Framework 4.0以前では、それまではHttpWebRequestクラス、WebClientが使用されていた。
HttpClientクラスは.NET Framework 4.5以降から提供された機能であり、簡単にHTTPリクエストを投げることができるクラスとして追加された。
HttpClientクラスの仕様
HttpClientクラスのインスタンスを生成する時、内部では新しいソケットを開く。
したがって、メソッド内でHttpClientクラスのインスタンスを生成する場合、常に新しいソケットを開くため、リソースを消費することになる。
HttpClientクラスのインスタンスを破棄した場合、ソケットが閉じるタイミングは、状態がTIME_WAITに遷移して、暫く時間が経つと自動的に解放される。
これは、リクエストする頻度が少ない場合は問題無いが、大量にリクエストを行う場合は大きなボトルネックとなる。
アンチパターン
HttpClientクラス
HttpClientクラスのインスタンスの生成において、IDisposableインターフェースを実装しているのでusingブロックで囲うものがある。
しかし、これは通信を実行するごとにソケットを開くことにより、大量のリソースを消費してリソースが枯渇する場合がある。
<syntaxhighlight lang="c#">
using (var client = new HttpClient())
{
await client.PostAsync("http://iketeru-service.com/");
}
</syntaxhighlight>
HttpRequestMessageクラス
固定のリクエストヘッダや認証情報を付加したHttpRequestMessageクラスを使用する場合、共通の内部メソッドであるCreateRequest()を使用する。
これは、HttpRequestMessageクラスのインスタンスを生成した後、SendAsync()メソッドを使用してメッセージを送信する。
<syntaxhighlight lang="c#">
var getReult = await client.GetAsync("http://kirakira-service.com/");
var postRsult = await client.PostAsync("http://sugoi-service.com/");
</syntaxhighlight>
解決策
HttpClientクラスは、privateキーワードおよびstaticキーワードを指定したプロパティとして持つ必要がある。
Microsoftの公式ドキュメント不適切なインスタンス化のアンチパターンの中でこの問題について取り上げており、
HttpClientを使用した実装をする時は、インスタンスを静的変数(static)にして使用するとの記載がある。
サンプルコード
まず、HttpClientクラスのオブジェクトを生成する。
この時、タイムアウトの設定等はコンストラクタで行う必要がある。
複数のHttoClientクラスを使用して同時に実行する場合も、HttpClientはそのような使用を想定した設計となっている。
<syntaxhighlight lang="c#">
class SmapleClass
{
private static readonly HttpClient httpclient = null;
static SampleClass()
{
httpclient = new HttpClient();
}
public async Task<SomeResponse> CallAPI()
{
await httpclient.PostAsync("{URL}");
...
}
}
</syntaxhighlight>
また、1つのHttpClientクラスは1つのソケット(1つのホスト)として使用した方がよいため、
異なるホストにもリクエストを投げる場合は、別のHttpClientクラスのオブジェクトを生成する方がよい。