【C#】IHttpClientFactoryを使ってHttpClientを正しく生成する方法

目次

概要

従来の 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ステップが必要です。

  1. 登録 (Startup.cs / Program.cs):C#services.AddHttpClient();
  2. 利用 (クラス側):
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>();

注意点

  1. Dispose不要: factory.CreateClient() で作成した HttpClient インスタンスは、原則として Dispose する必要がありません(しても問題ありませんが、内部のリソース管理はファクトリが行います)。
  2. シングルトン利用: 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 メソッド一つで完結するため、導入コストも低く効果的です。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次