「C Sharpとネットワーク - HttpClient」の版間の差分

編集の要約なし
(文字列「</source>」を「</syntaxhighlight>」に置換)
編集の要約なし
1行目: 1行目:
== 概要 ==
== 概要 ==
HttpClientは、アプリケーションにおいてHTTPリクエストを投げたい時に使用するクラスである。<br>
<code>HttpClient</code>クラスは、HTTPリクエストを投げる場合に使用するクラスである。<br>
.NET Framework 4.5から提供された機能で、それまではHttpWebRequestやWebClientが存在したが、<br>
<br>
簡単にHTTPリクエストを投げられるクラスとして追加された。<br><br>
.NET Framework 4.0以前では、それまでは<code>HttpWebRequest</code>クラス、<code>WebClient</code>が使用されていた。<br>
<code>HttpClient</code>クラスは.NET Framework 4.5以降から提供された機能であり、簡単にHTTPリクエストを投げることができるクラスとして追加された。<br>
<br><br>
 
== HttpClientクラスの仕様 ==
<code>HttpClient</code>クラスのインスタンスを生成する時、内部では新しいソケットを開く。<br>
したがって、メソッド内で<code>HttpClient</code>クラスのインスタンスを生成する場合、常に新しいソケットを開くため、リソースを消費することになる。<br>
<br>
<code>HttpClient</code>クラスのインスタンスを破棄した場合、ソケットが閉じるタイミングは、状態が<code>TIME_WAIT</code>に遷移して、暫く時間が経つと自動的に解放される。<br>
<br>
これは、リクエストする頻度が少ない場合は問題無いが、大量にリクエストを行う場合は大きなボトルネックとなる。<br>
<br><br>


== HttpClientの仕様 ==
== アンチパターン ==
HttpClientをインスタンス生成した時、内部では新しいソケットをオープンしている。<br>
==== HttpClientクラス ====
つまり、メソッドでHttpClientのインスタンスを生成すると、常に新しいソケットをオープンして、リソースを消費することになる。<br>
<code>HttpClient</code>クラスのインスタンスの生成において、<code>IDisposable</code>インターフェースを実装しているので<code>using</code>ブロックで囲うものがある。<br>
HttpClientのインスタンスを破棄した場合、ソケットがクローズされるタイミングは、状態がTIME_WAITに遷移して、暫く時間が経ってから解放される。<br>
<br>
これはリクエストする回数が少ないのであれば問題は無いが、大量にリクエストを行う場合は大きなボトルネックとなる。<br><br>
しかし、これは通信を実行するごとにソケットを開くことにより、大量のリソースを消費してリソースが枯渇する場合がある。<br>
<syntaxhighlight lang="c#">
using (var client = new HttpClient())
{
    await client.PostAsync("http://iketeru-service.com/");
}
</syntaxhighlight>
<br>
==== HttpRequestMessageクラス ====
固定のリクエストヘッダや認証情報を付加した<code>HttpRequestMessage</code>クラスを使用する場合、共通の内部メソッドである<code>CreateRequest()</code>を使用する。<br>
これは、<code>HttpRequestMessage</code>クラスのインスタンスを生成した後、<code>SendAsync()</code>メソッドを使用してメッセージを送信する。<br>
<br>
<syntaxhighlight lang="c#">
var getReult = await client.GetAsync("http://kirakira-service.com/");
var postRsult = await client.PostAsync("http://sugoi-service.com/");
</syntaxhighlight>
<br><br>


== 解決策 ==
== 解決策 ==
<code>HttpClient</code>クラスは、<code>private</code>キーワードおよび<code>static</code>キーワードを指定したプロパティとして持つ必要がある。<br>
<br>
Microsoftの公式ドキュメント[https://docs.microsoft.com/ja-jp/azure/architecture/antipatterns/improper-instantiation/ 不適切なインスタンス化のアンチパターン]の中でこの問題について取り上げており、<br>
Microsoftの公式ドキュメント[https://docs.microsoft.com/ja-jp/azure/architecture/antipatterns/improper-instantiation/ 不適切なインスタンス化のアンチパターン]の中でこの問題について取り上げており、<br>
HttpClientを使用した実装をする時は、インスタンスを静的変数(static)にして使用するとの記載がある。<br>
HttpClientを使用した実装をする時は、インスタンスを静的変数(static)にして使用するとの記載がある。<br>
下記のサンプルコードに実装方法を示す。<br><br>
<br><br>


== サンプルコード ==
== サンプルコード ==
  <syntaxhighlight lang="cpp">
まず、<code>HttpClient</code>クラスのオブジェクトを生成する。<br>
この時、タイムアウトの設定等はコンストラクタで行う必要がある。<br>
<br>
複数の<code>HttoClient</code>クラスを使用して同時に実行する場合も、<code>HttpClient</code>はそのような使用を想定した設計となっている。<br>
<br>
  <syntaxhighlight lang="c#">
  class SmapleClass
  class SmapleClass
  {
  {
34行目: 68行目:
  </syntaxhighlight>
  </syntaxhighlight>
<br>
<br>
上記のように記述して、HttpClientのオブジェクトを使用する。(TimeOutの設定等はコンストラクタで行う)<br>
また、1つの<code>HttpClient</code>クラスは1つのソケット(1つのホスト)として使用した方がよいため、<br>
同時実行の場合も、HttpClientはそのような利用を想定した設計となっている。<br><br>
異なるホストにもリクエストを投げる場合は、別の<code>HttpClient</code>クラスのオブジェクトを生成する方がよい。<br>
<br><br>


また、他の注意点を挙げると、1つのHttpClientオブジェクトで1つのソケット(1つのホスト)なので、<br>
異なるホストにもリクエストを投げる場合は、別のオブジェクトを生成する方が良い。<br><br>


__FORCETOC__
__FORCETOC__
[[カテゴリ:C_Sharp]]
[[カテゴリ:C_Sharp]]