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

📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)

101行目: 101行目:


== ソリューション ==
== ソリューション ==
==== 手順 ====
==== 方法 1 : static / readonly ====
<code>HttpClient</code>クラスは、<code>private</code>キーワードおよび<code>static</code>キーワードを指定したプロパティとして持つ必要がある。<br>
<code>HttpClient</code>クラスは、<code>private</code>キーワードおよび<code>static</code>キーワードを指定したプロパティとして持つ必要がある。<br>
<br>
<br>
107行目: 107行目:
HttpClientを使用した実装をする時は、インスタンスを静的変数(static)にして使用するとの記載がある。<br>
HttpClientを使用した実装をする時は、インスタンスを静的変数(static)にして使用するとの記載がある。<br>
<br>
<br>
==== サンプルコード ====
まず、<code>HttpClient</code>クラスのオブジェクトを生成する。<br>
まず、<code>HttpClient</code>クラスのオブジェクトを生成する。<br>
この時、タイムアウトの設定等はコンストラクタで行う必要がある。<br>
この時、タイムアウトの設定等はコンストラクタで行う必要がある。<br>
145行目: 144行目:
また、1つの<code>HttpClient</code>クラスは1つのソケット(1つのホスト)として使用した方がよいため、<br>
また、1つの<code>HttpClient</code>クラスは1つのソケット(1つのホスト)として使用した方がよいため、<br>
異なるホストにもリクエストを投げる場合は、別の<code>HttpClient</code>クラスのオブジェクトを生成する方がよい。<br>
異なるホストにもリクエストを投げる場合は、別の<code>HttpClient</code>クラスのオブジェクトを生成する方がよい。<br>
<br>
==== 方法 2 : HttpClientFactory (単一のベースURI) ====
* 依存性注入 (DI) の設定
*: Host.CreateDefaultBuilderメソッドを使用して、.NETの標準的なDIコンテナを設定する。
*: サービスの登録はConfigureServicesメソッドで行う。
*: 異なるライフタイムスコープ (Transient, Scoped, Singleton) から適切なものを選択する。
<br>
HttpClientFactoryでは、2つのパターンがある。<br>
* 名前付きHttpClient
*: services.AddHttpClient("github", ...) で登録する。
*: IHttpClientFactory.CreateClient("github")で取得する。
*: 同じ名前で登録されたクライアントは同じ設定を共有する。
*: <br>
* 型付きHttpClient
*: services.AddHttpClient<GitHubService>メソッドで登録する。
*: コンストラクタインジェクションで自動的に注入する。
*: サービスごとに特化した実装が可能になる。
<br>
Nugetを使用して、以下に示すライブラリをインストールする。<br>
* Microsoft.Extensions.Http
* Microsoft.Extensions.Hosting
<br>
<syntaxhighlight lang="c#">
using System;
using System.Threading.Tasks;
using System.Net.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
class Program
{
    static async Task Main(string[] args)
    {
        // GenericHostを使用してアプリケーションを構築
        // これにより、依存性注入、構成、ログ等の機能が利用可能になる
        var host = Host.CreateDefaultBuilder(args).ConfigureServices((context, services) => {
          // 方法 1 : 名前付きHttpClientを使用する場合
          // 名前付きHttpClientの登録
          // "github"という名前で、GitHubのAPIにアクセスするためのHttpClientを設定
          services.AddHttpClient("github", client => {
              // ベースとなるURIを設定
              client.BaseAddress = new Uri("https://api.github.com/");
              // User-Agentヘッダを設定 (GitHubのAPIでは必須)
              client.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
          });
          // 方法 2 : 型付きHttpClientを使用する場合
          // 型付きHttpClientの登録
          // GitHubServiceクラスに特化したHttpClientを自動的に注入
          services.AddHttpClient<GitHubService>();
          // ExampleServiceをDIコンテナに登録
          // TransientスコープでサービスをDIコンテナに登録(毎回新しいインスタンスが作成される)
          services.AddTransient<IExampleService, ExampleService>();
        }).Build();
        // DIコンテナからサービスを取得し、実行
        var service = host.Services.GetRequiredService<IExampleService>();
        await service.RunExample();
    }
}
/// <summary>
/// 型付きHttpClientを使用するサービスクラス
/// GitHubのAPIに特化した操作を提供
/// </summary>
public class GitHubService
{
    private readonly HttpClient _httpClient;
    // コンストラクタインジェクション
    // DIコンテナにより、設定済みのHttpClientが自動的に注入される
    public GitHubService(HttpClient client)
    {
      _httpClient = client;
      // このHttpClientインスタンスに対する固有の設定
      _httpClient.BaseAddress = new Uri("https://api.github.com/");
      _httpClient.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
    }
    /// <summary>
    /// GitHubのAPIからデータを取得する
    /// </summary>
    /// <returns>API応答の文字列</returns>
    public async Task<string> GetApiResponse()
    {
      // dotnet/runtimeリポジトリの情報を取得
      return await _httpClient.GetStringAsync("repos/dotnet/runtime");
    }
}
/// <summary>
/// サービスのインターフェース定義
/// 依存性の注入とテストを容易にするために使用
/// </summary>
public interface IExampleService
{
    Task RunExample();
}
/// <summary>
/// HttpClientFactoryの使用例を示すサービスクラス
/// 名前付きHttpClientと型付きHttpClientの両方の使用例を提供
/// </summary>
public class ExampleService : IExampleService
{
    private readonly IHttpClientFactory _clientFactory;
    private readonly GitHubService _githubService;
    /// <summary>
    /// コンストラクタで依存関係を注入
    /// </summary>
    /// <param name="clientFactory">HttpClientFactory - 名前付きクライアントの作成に使用</param>
    /// <param name="githubService">GitHubService - 型付きHttpClientの例として使用</param>
    public ExampleService(IHttpClientFactory clientFactory, GitHubService githubService)
    {
      _clientFactory = clientFactory;
      _githubService = githubService;
    }
    /// <summary>
    /// HttpClientFactoryの両方の使用パターンを実演
    /// </summary>
    public async Task RunExample()
    {
      // 方法 1 : 名前付きHttpClientの使用例
      try
      {
          // "github"という名前で設定されたHttpClientを取得
          var client = _clientFactory.CreateClient("github");
          var response = await client.GetStringAsync("repos/dotnet/runtime");
          Console.WriteLine("Named HttpClient Response:");
          Console.WriteLine(response.Substring(0, 200) + "...");
      }
      catch (Exception ex)
      {
          Console.WriteLine($"Named client error: {ex.Message}");
      }
      // // 方法 2 : 型付きHttpClientの使用例
      try
      {
          // 注入されたGitHubServiceを使用
          var response = await _githubService.GetApiResponse();
          Console.WriteLine("Typed HttpClient Response:");
          Console.WriteLine(response.Substring(0, 200) + "...");
      }
      catch (Exception ex)
      {
          Console.WriteLine($"Typed client error: {ex.Message}");
      }
    }
}
</syntaxhighlight>
<br>
==== 方法 3 : HttpClientFactory (複数のベースURI) ====
<br><br>
<br><br>