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

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

 
(同じ利用者による、間の1版が非表示)
301行目: 301行目:
<br>
<br>
==== 方法 3 : HttpClientFactory (複数のベースURI) ====
==== 方法 3 : HttpClientFactory (複数のベースURI) ====
* 名前付きHttpClientを使用する方法
** メリット
**: 個別の設定が容易
** デメリット
**: 文字列ベースの名前指定
**: 型安全性が低い
*: <br>
* 型付きHttpClientを使用する方法
** メリット
**: 型安全性が高い
**: APIごとに特化した実装が可能
**: テストが容易
** デメリット
**: クラス数が増加
**: 各APIに対して個別の実装が必要
*: <br>
* 動的にベースURIを切り替える方法
** メリット
**: 柔軟性が高い
**: 設定ファイルでの管理が容易
**: 実行時の切り替えが可能
** デメリット
**: 複雑な実装
<br>
<syntaxhighlight lang="json">
# 動的なベースURI切り替えで使用
# appsettings.json
{
  "ApiSettings": {
    "BaseUrls": {
      "github": "https://api.github.com/",
      "weather": "https://api.weather.com/",
      "other": "https://api.other.com/"
    }
  }
}
</syntaxhighlight>
<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)
    {
      var host = Host.CreateDefaultBuilder(args).ConfigureServices((context, services) => {
          // 方法 1 : 異なる名前で複数のHttpClientを登録
          services.AddHttpClient("github", client => {
            client.BaseAddress = new Uri("https://api.github.com/");
            client.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
          });
          services.AddHttpClient("weather", client => {
            client.BaseAddress = new Uri("https://api.weather.com/");
            client.DefaultRequestHeaders.Add("User-Agent", "Weather-Service");
          });
          // 方法 2 : 型付きHttpClientを各APIサービス用に登録
          services.AddHttpClient<GitHubService>();
          services.AddHttpClient<WeatherService>();
          // 方法 3 : 設定情報を含むサービスを登録
          services.Configure<ApiSettings>(context.Configuration.GetSection("ApiSettings"));
          services.AddHttpClient<MultiBaseUriService>();
          services.AddTransient<IMultiApiService, MultiApiService>();
      }).Build();
      var service = host.Services.GetRequiredService<IMultiApiService>();
      await service.RunExample();
    }
}
// APIの設定を保持するクラス
public class ApiSettings
{
    public Dictionary<string, string> BaseUrls { get; set; } = new();
}
// 複数のベースURIを扱うサービス
public class MultiBaseUriService
{
    private readonly HttpClient _httpClient;
    private readonly ApiSettings _settings;
    private readonly Dictionary<string, string> _baseUrls;
    public MultiBaseUriService(HttpClient client, IOptions<ApiSettings> settings)
    {
      _httpClient = client;
      _settings = settings.Value;
      _baseUrls = _settings.BaseUrls;
    }
    public async Task<string> SendRequest(string apiKey, string endpoint)
    {
      if (!_baseUrls.TryGetValue(apiKey, out var baseUrl))
      {
          throw new ArgumentException($"Unknown API key: {apiKey}");
      }
      var fullUrl = new Uri(new Uri(baseUrl), endpoint);
      return await _httpClient.GetStringAsync(fullUrl);
    }
}
// GithubのAPI用サービス
public class GitHubService
{
    private readonly HttpClient _httpClient;
    public GitHubService(HttpClient client)
    {
      _httpClient = client;
      _httpClient.BaseAddress = new Uri("https://api.github.com/");
      _httpClient.DefaultRequestHeaders.Add("User-Agent", "GitHub-Service");
    }
    public async Task<string> GetRepositoryInfo(string repo)
    {
      return await _httpClient.GetStringAsync($"repos/{repo}");
    }
}
// 気象API用サービス
public class WeatherService
{
    private readonly HttpClient _httpClient;
    public WeatherService(HttpClient client)
    {
      _httpClient = client;
      _httpClient.BaseAddress = new Uri("https://api.weather.com/");
      _httpClient.DefaultRequestHeaders.Add("User-Agent", "Weather-Service");
    }
    public async Task<string> GetWeatherInfo(string location)
    {
      return await _httpClient.GetStringAsync($"weather/{location}");
    }
}
// 複数APIを利用するサービスのインターフェース
public interface IMultiApiService
{
    Task RunExample();
}
// 複数のAPIを利用する実装
public class MultiApiService : IMultiApiService
{
    private readonly IHttpClientFactory  _clientFactory;
    private readonly GitHubService      _githubService;
    private readonly WeatherService      _weatherService;
    private readonly MultiBaseUriService _multiBaseUriService;
    public MultiApiService(IHttpClientFactory clientFactory, GitHubService githubService, WeatherService weatherService,
                          MultiBaseUriService multiBaseUriService)
    {
      _clientFactory = clientFactory;
      _githubService = githubService;
      _weatherService = weatherService;
      _multiBaseUriService = multiBaseUriService;
    }
    public async Task RunExample()
    {
      // 方法 1 : 名前付きHttpClientの使用
      try
      {
          var githubClient = _clientFactory.CreateClient("github");
          var weatherClient = _clientFactory.CreateClient("weather");
          var githubResponse = await githubClient.GetStringAsync("repos/dotnet/runtime");
          var weatherResponse = await weatherClient.GetStringAsync("weather/tokyo");
          Console.WriteLine("Named Clients Response:");
          Console.WriteLine($"GitHub: {githubResponse.Substring(0, 100)}...");
          Console.WriteLine($"Weather: {weatherResponse.Substring(0, 100)}...");
      }
      catch (Exception ex)
      {
          Console.WriteLine($"Named clients error: {ex.Message}");
      }
      // 方法 2 : 型付きHttpClientの使用
      try
      {
          var githubInfo = await _githubService.GetRepositoryInfo("dotnet/runtime");
          var weatherInfo = await _weatherService.GetWeatherInfo("tokyo");
          Console.WriteLine("\nTyped Clients Response:");
          Console.WriteLine($"GitHub: {githubInfo.Substring(0, 100)}...");
          Console.WriteLine($"Weather: {weatherInfo.Substring(0, 100)}...");
      }
      catch (Exception ex)
      {
          Console.WriteLine($"Typed clients error: {ex.Message}");
      }
      // 方法 3 : 動的なベースURI切り替え
      try
      {
          var githubResponse = await _multiBaseUriService.SendRequest("github", "repos/dotnet/runtime");
          var weatherResponse = await _multiBaseUriService.SendRequest("weather", "weather/tokyo");
          Console.WriteLine("\nMulti Base URI Service Response:");
          Console.WriteLine($"GitHub: {githubResponse.Substring(0, 100)}...");
          Console.WriteLine($"Weather: {weatherResponse.Substring(0, 100)}...");
      }
      catch (Exception ex)
      {
          Console.WriteLine($"Multi base URI error: {ex.Message}");
      }
    }
}
</syntaxhighlight>
<br><br>
<br><br>