Tutorial/C# と .NET

C#と.NETで為替レートを取得する

IHttpClientFactory、decimal、キャンセル、有限のタイムアウト、情報源を保つ応答処理で型付き.NETクライアントを作る。

MMexchangerate.dev·Jul 17, 2026·6分で読了

exchangerate.dev用の型付きHttpClientを登録し、設定からAPIキーを注入し、レートをdecimalへ変換する。キャンセルとタイムアウトを明示して、遅い上流呼び出しがアプリケーション要求を長時間保持しないようにする。

Key points
接続再利用と一元設定にIHttpClientFactoryを使う。
レートをdecimalへ変換し、鮮度フィールドも保持する。
すべての呼び出しにCancellationTokenを渡し、タイムアウトを設定する。
デコード前にEnsureSuccessStatusCode()を呼ぶ。

型付きHttpClientを登録する

登録がベースURL、bearer token、タイムアウトを管理する。型付きクライアントは応答契約を持ち、呼び出し元のキャンセルをネットワーク要求へ渡す。

csharp · Program.cs and FxClient.cscopy
// Program.cs
using System.Net.Http.Headers;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHttpClient<FxClient>(client =>
{
    var key = builder.Configuration["EXCHANGERATE_API_KEY"]
        ?? throw new InvalidOperationException("EXCHANGERATE_API_KEY is missing");

    client.BaseAddress = new Uri("https://api.exchangerate.dev/v1/");
    client.DefaultRequestHeaders.Authorization =
        new AuthenticationHeaderValue("Bearer", key);
    client.Timeout = TimeSpan.FromSeconds(5);
});

// FxClient.cs
using System.Net.Http.Json;
using System.Text.Json.Serialization;

public sealed record LatestRates(
    string Base,
    string Source,
    [property: JsonPropertyName("market_session")] string MarketSession,
    [property: JsonPropertyName("data_updated_at")] DateTimeOffset DataUpdatedAt,
    Dictionary<string, decimal> Rates
);

public sealed class FxClient(HttpClient http)
{
    public async Task<LatestRates> GetLatestAsync(
        string baseCurrency,
        CancellationToken cancellationToken)
    {
        using var response = await http.GetAsync(
            $"latest/{baseCurrency}?symbols=EUR,GBP",
            cancellationToken);

        response.EnsureSuccessStatusCode();

        return await response.Content.ReadFromJsonAsync<LatestRates>(
            cancellationToken: cancellationToken)
            ?? throw new InvalidOperationException("Empty FX response");
    }
}

要求からキャンセルを渡す

csharp · endpoint usagecopy
var app = builder.Build();

app.MapGet("/fx", async (
    FxClient fx,
    CancellationToken cancellationToken) =>
{
    var rates = await fx.GetLatestAsync("USD", cancellationToken);

    return Results.Ok(new {
        eur = rates.Rates["EUR"],
        rates.Source,
        rates.MarketSession,
        rates.DataUpdatedAt,
    });
});

app.Run();

成功した観測だけをキャッシュする

共有キャッシュにはRates["EUR"]だけでなく完全な観測を保存する。SourceMarketSessionDataUpdatedAtがあれば、取引日のライブ更新と日次・閉場値を区別できる。

再試行の対象を絞る
短いネットワーク障害や選択した5xxだけを小さなバックオフで再試行する。401を一時障害として扱わず、429後に再試行の集中を作らない。
  • 型付きクライアント登録を1つにする。
  • レートと金額にdecimalを使う。
  • 呼び出し全体にキャンセルを渡す。
  • 非成功応答を変換前に拒否する。
MM
exchangerate.dev
FXデータを扱う開発者向けの統合ガイド。

Keep reading

Guide1回の呼び出しで過去のFX時系列を取得するRead Referencesourceとmarket_sessionの読み方Read Guideインディケーティブレートと約定可能レートRead