ASP.NET Core: IHttpClientFactoryのサンプル

前回の記事でIHttpClientFactoryの使用方法を説明しました。
ここでは、サンプルを使用した具体的な使用方法を説明します。

前提

  • マイクロソフトが推奨するIHttpClientFactoryを使用して、HttpClientクライアントを取得する前提です。
  • HttpClientの使い方は何種類かありますが、ここでは既定のクライアント、名前付きクライアントを前提とします。
    実際の業務では、名前付き/型付きクライアントを使う場合が多いと思われますが、HttpClientとしての使用法は大きく変わらないため。
  • サンプルはWindows10 + Visual Studio 2019(ASP.NET Core 3.1)環境で確認しています。

HttpClientの基本的な使い方

サービスにクライアントを登録・構成し、
必要なタイミングでクライアントを取得してHTTP要求を実行する流れになります。

サービスへのクライアントの追加と構成

次のようにStartup.csでAddHttpClient()を使ってクライアントを登録します。
下記の例のようにクライアントの構成を行う他に、独自に要求/応答をカスタマイズするためのハンドラやエラー処理をカスタマイズするためのPollyポリシーを設定することもできます。

HTTP要求の実行

自由度の高いHTTP要求を作成できるSendAsync()を使うか、
より簡潔にHTTP要求を作成できるGetAsync()/PostAsync()等の便利なメソッドを使用する方法があります。

汎用的な方法: SendAsync()の使用

HTTP要求を表現するHttpRequestMessageオブジェクトを作成し、HTTPメソッドやURIの指定、必要に応じてHTTPヘッダやコンテンツ(ボディ)を指定します。
このオブジェクトを引数として、HttpClientのSendAsync()を実行します。HTTP応答はHttpResponseMessageに格納され、ステータスコードの確認、必要に応じてHTTPヘッダやコンテンツを取得できます。

  • 既定のクライアントや名前付きクライアントの場合、コンストラクタで定義したIHttpClientFactoryからクライアントを取得する必要があります。(コンストラクタでIHttpClientFactoryを引数宣言するとDependency Injectionの仕組みでインスタンスが設定されます。)
  • HttpRequestMessageでは、HeadersプロパティでHTTPヘッダの編集、Contentプロパティでコンテンツ(HTTPボディ相当)を設定ができます。
  • ContentプロパティはHttpContent型となっており、このクラスを継承した次のコンテンツを指定できます。詳細はリファレンスを参照のこと。
    コンテンツ(クラス)説明
    StringContentテキスト形式のコンテンツ
    Content-Typeの既定は”text/plain; charset=utf-8″であり、コンストラクタの引数やHeadersプロパティから指定可。
    StreamContent
    ByteArrayContent
    ストリーム型・バイト配列型のコンテンツ
    既定のContent-Typeが指定されないので、Headers.ContentTypeプロパティやHttpRequestMessageで指定することになります。
    FormUrlEncodedContentフォーム形式のコンテンツ
    input要素で入力した想定の形式です。
    Content-Typeは”application/x-www-form-urlencoded”になります。
    MultipartFormDataContentマルチパートフォーム形式のコンテンツ
    input要素で入力した想定の形式で、ファイルアップロードの場合に使用する。
    Content-Typeは”multipart/form-data; boundary=…”になります。
    MultipartContent任意のマルチパート形式のコンテンツ
    Webアプリでマルチパート形式を使用する場合、上記の”multipart/form-data”になるので、このコンテンツを使用することはないと思います。MultipartFormDataContentの基底クラスです。

簡潔な方法: GetAync(), PostAsync()等の使用

StringContent等のコンテンツを使ってHTTP要求を実行できます。
HttpRequestMessageオブジェクトを作成する必要がなく、前述の汎用的な方法より簡潔に実装できます。
この方法では、HTTPメソッドに対応するGetAsync(), PostAsync(), PutAsync(), DeleteAsync()が提供されています。これらのメソッドに対して、URIとコンテンツを引数してHTTP要求を実行します。

参考

  • 常時付与するHTTPヘッダがある場合、Startup時のAddHttpClientオプション(HttpClient.DefaultRequestHeaders)で指定することをお薦めします。
  • 業務アプリの開発では、開発環境と本番環境等のように実行環境に応じて、ベースURIを切り替えられるようにしたい場合があります。Startup時のAddHttpClientオプション(HttpClient.BaseAddress)で”https://xxxx/”等のベースのURIを指定し、個別のHttpClientの呼び出しでは”/api/xxx”等の相対パスを指定するような実装をお薦めします。

サンプル

ここではPOST/GETを使った基本的なサンプルを説明します。

このサンプルでは、ASP.NET Core MVCのコントローラからIHttpClientFactoryを使って、ローカルのAPIコントローラにHTTP要求を発行しています。
各サンプルでは、次のように名前付きクライアントとして登録した”basic”を使用しています。

サンプルのプロジェクトや完全なソースコードは下記をご覧ください

GitHub

クエリ文字列を指定してGET実行

クエリ文字列の作成は、.NET Core 3系から標準で含まれるWebUtilitiesのQueryHelpersを使用できます。
HTTP要求の送信はHttpClientのGetAsync()で行います。DELETEを実行する場合はDeleteAsync()を使用します。

生成されるHTTP要求は次のようになります。
(ログに出力されるURLを見るとarg1はURLエンコードあり、arg2はURLエンコードなしに見えますが、実際にはどちらもURLエンコードされていました。)

HTTPヘッダを指定してGET実行

上記の方法だとクライアント登録時の構成でしかHTTPヘッダを指定できません。
このような場合は汎用的な方法を使います。

生成されるHTTP要求は次のようになります。

フォーム形式によるPOST実行

FormUrlEncodedContentオブジェクトにキーと値を格納し、HTTP要求を発行します。
Content-Typeは”application/x-www-form-urlencoded”になります。

生成されるHTTP要求は次のようになります。

マルチパートフォーム形式によるPOST実行

MultipartFormDataContentオブジェクトにキーと値を格納し、HTTP要求を発行します。
値として、アップロードするファイル内容を表現するストリームやバイト配列を指定できます。
Content-Typeは”multipart/form-data”になります。

生成されるHTTP要求は次のようになります。

プロキシの使用

HttpClientが実際の通信を行う際、内部でメッセージハンドラを使用しています。
.NET Core 2.1以降では、既定のメッセージハンドラとしてSocketsHttpHandlerが使用されており、このプロパティでプロキシを指定できます。
詳細はSocketsHttpHandlerのリファレンスを参照のことですが、プロキシ以外にもCookieやコネクションタイムアウト等の細かい設定が可能です。.NET Core 2.1より前の既定のメッセージハンドラはHttpClientHandlerでした。HttpClientHandlerに比べ、SocketsHttpHandlerはより高性能でプラットフォーム非依存とのことです。

ローカルで検証用に構築したプロキシサーバ(Apache HTTPサーバ)を使って動作を確認します。
このプロキシサーバの構築についてはこちらをご覧ください。

出だしだけですが、生成されるHTTP要求の例は次のようになります。