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

提供:MochiuWiki : SUSE, EC, PCB
ナビゲーションに移動 検索に移動
(文字列「</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]]

2024年1月23日 (火) 08:24時点における版

概要

HttpClientクラスは、HTTPリクエストを投げる場合に使用するクラスである。

.NET Framework 4.0以前では、それまではHttpWebRequestクラス、WebClientが使用されていた。
HttpClientクラスは.NET Framework 4.5以降から提供された機能であり、簡単にHTTPリクエストを投げることができるクラスとして追加された。


HttpClientクラスの仕様

HttpClientクラスのインスタンスを生成する時、内部では新しいソケットを開く。
したがって、メソッド内でHttpClientクラスのインスタンスを生成する場合、常に新しいソケットを開くため、リソースを消費することになる。

HttpClientクラスのインスタンスを破棄した場合、ソケットが閉じるタイミングは、状態がTIME_WAITに遷移して、暫く時間が経つと自動的に解放される。

これは、リクエストする頻度が少ない場合は問題無いが、大量にリクエストを行う場合は大きなボトルネックとなる。


アンチパターン

HttpClientクラス

HttpClientクラスのインスタンスの生成において、IDisposableインターフェースを実装しているのでusingブロックで囲うものがある。

しかし、これは通信を実行するごとにソケットを開くことにより、大量のリソースを消費してリソースが枯渇する場合がある。

 using (var client = new HttpClient())
 {
    await client.PostAsync("http://iketeru-service.com/");
 }


HttpRequestMessageクラス

固定のリクエストヘッダや認証情報を付加したHttpRequestMessageクラスを使用する場合、共通の内部メソッドであるCreateRequest()を使用する。
これは、HttpRequestMessageクラスのインスタンスを生成した後、SendAsync()メソッドを使用してメッセージを送信する。

 var getReult = await client.GetAsync("http://kirakira-service.com/");
 var postRsult = await client.PostAsync("http://sugoi-service.com/");



解決策

HttpClientクラスは、privateキーワードおよびstaticキーワードを指定したプロパティとして持つ必要がある。

Microsoftの公式ドキュメント不適切なインスタンス化のアンチパターンの中でこの問題について取り上げており、
HttpClientを使用した実装をする時は、インスタンスを静的変数(static)にして使用するとの記載がある。


サンプルコード

まず、HttpClientクラスのオブジェクトを生成する。
この時、タイムアウトの設定等はコンストラクタで行う必要がある。

複数のHttoClientクラスを使用して同時に実行する場合も、HttpClientはそのような使用を想定した設計となっている。

 class SmapleClass
 {
    private static readonly HttpClient httpclient = null;
    
    static SampleClass()
    {
        httpclient = new HttpClient();
    }

    public async Task<SomeResponse> CallAPI()
    {
       await httpclient.PostAsync("{URL}");
       ...
    }
 }


また、1つのHttpClientクラスは1つのソケット(1つのホスト)として使用した方がよいため、
異なるホストにもリクエストを投げる場合は、別のHttpClientクラスのオブジェクトを生成する方がよい。