概要
従来の new HttpClient() の使い回しや使い捨てによって発生する「ソケット枯渇問題」や「DNS変更が反映されない問題」を解決するために、推奨されている IHttpClientFactory を使用する実装パターンです。 Dependency Injection (DI) コンテナを介してファクトリを注入し、そこから適切な設定が施された HttpClient インスタンスを生成します。
仕様(入出力)
- 入力: Web APIのURL。
- 出力:
IHttpClientFactory経由で生成されたクライアントによるAPIコールの結果。 - 前提: .NET Core 2.1以上(推奨は .NET 6.0以上)。
Microsoft.Extensions.Httpパッケージが必要。
基本の使い方
DIコンテナへの登録と、クラスでの受け取り(注入)の2ステップが必要です。
- 登録 (
Startup.cs/Program.cs):C#services.AddHttpClient(); - 利用 (クラス側):
public class MyService
{
private readonly IHttpClientFactory _factory;
public MyService(IHttpClientFactory factory)
{
_factory = factory;
}
public async Task DoWork()
{
// ここでクライアントを生成
var client = _factory.CreateClient();
var response = await client.GetAsync("...");
}
}
コード全文
ここではコンソールアプリケーションで ServiceCollection (DIコンテナ) を手動で構築し、IHttpClientFactory を利用可能にする完全なコード例を示します。
必要なパッケージ:
dotnet add package Microsoft.Extensions.Http
dotnet add package Microsoft.Extensions.DependencyInjection
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection; // DI用
class Program
{
static async Task Main()
{
// 1. DIコンテナのセットアップ
var services = new ServiceCollection();
// HttpClient機能を登録 (AddHttpClient)
services.AddHttpClient();
// HttpClientを利用するワーカクラスを登録
services.AddTransient<MyWorker>();
// プロバイダの作成
var serviceProvider = services.BuildServiceProvider();
// 2. ワーカクラスの取得と実行
var worker = serviceProvider.GetRequiredService<MyWorker>();
try
{
await worker.RunAsync();
}
catch (Exception ex)
{
Console.WriteLine($"エラー: {ex.Message}");
}
}
}
// 実際にHTTP通信を行うクラス
public class MyWorker
{
private readonly IHttpClientFactory _clientFactory;
// コンストラクタ注入でファクトリを受け取る
public MyWorker(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task RunAsync()
{
// 3. ファクトリからHttpClientを生成
// 内部でハンドラのライフサイクルが管理されています
var client = _clientFactory.CreateClient();
string url = "http://httpbin.org/get";
Console.WriteLine($"アクセス中: {url}");
// 通常通り使用
string result = await client.GetStringAsync(url);
Console.WriteLine("--- 取得結果 ---");
// 結果の一部を表示
Console.WriteLine(result.Substring(0, Math.Min(result.Length, 200)));
}
}
カスタムポイント
- 名前付きクライアント (Named Clients): 特定のAPIごとにベースURLやヘッダーをあらかじめ設定しておきたい場合に使用します。C#
// 登録時 services.AddHttpClient("GitHub", c => { c.BaseAddress = new Uri("https://api.github.com/"); c.DefaultRequestHeaders.Add("User-Agent", "C# App"); }); // 利用時 var client = _factory.CreateClient("GitHub"); - 型付きクライアント (Typed Clients): 文字列で名前を指定するのではなく、特定のクラス専用のクライアントを作る、より推奨される方法です。C#
services.AddHttpClient<GitHubService>();
注意点
- Dispose不要:
factory.CreateClient()で作成したHttpClientインスタンスは、原則としてDisposeする必要がありません(しても問題ありませんが、内部のリソース管理はファクトリが行います)。 - シングルトン利用:
IHttpClientFactory自体はシングルトンとして登録されますが、そこから生成されるHttpClientは一時的なものです。しかし、内部のメッセージハンドラ(接続を管理する部品)はプールされて再利用されるため、効率的な通信が可能です。
応用
ポリシー(リトライ処理など)の適用
Microsoft.Extensions.Http.Polly パッケージを併用することで、通信失敗時のリトライ設定などを宣言的に記述できます。
// タイムアウトや500エラー時に3回リトライする設定
services.AddHttpClient("MyClient")
.AddTransientHttpErrorPolicy(builder =>
builder.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(600)));
まとめ
.NET Core以降のアプリケーションにおいてHTTP通信を行う際は、直接 new HttpClient() をするのではなく IHttpClientFactory を介してインスタンスを取得するのがベストプラクティスです。これにより、TCPソケットの枯渇問題やDNS変更の追従漏れといったネットワーク固有のトラブルをフレームワークレベルで回避し、安定した通信機能を実現することができます。DIコンテナへの登録は AddHttpClient メソッド一つで完結するため、導入コストも低く効果的です。
