Tutorial/C# 同 .NET

喺 C# 同 .NET 攞匯率

用 IHttpClientFactory、decimal、取消、有限逾時同埋保留來源嘅處理,整一個有類型嘅 .NET 匯率客戶端。

ERexchangerate.dev·Jul 17, 2026·6 分鐘閱讀

為 exchangerate.dev 註冊一個有類型嘅 HttpClient,密鑰由設定度注入,將匯率反序列化做 decimal。取消要傳到落去,仲要設定有限逾時。

Key points
IHttpClientFactory 管理連線同客戶端設定。
將匯率反序列化做 decimal,仲要保留新鮮度欄位。
傳遞 CancellationToken,仲要設定逾時。
解碼之前call EnsureSuccessStatusCode()

註冊一個有類型嘅 HttpClient

註冊設定基礎 URL、bearer token 同逾時。客戶端負責管理回應合約,仲要將個caller嘅取消傳去網絡請求度。

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 之後造成重試潮。
  • 保留一個有類型嘅客戶端註冊。
  • 匯率同金額用 decimal。
  • 喺成條call chain都要傳遞取消。
  • 反序列化之前要拒絕非成功嘅回應。
ER
exchangerate.dev
為用緊外匯數據嘅開發者而設嘅整合指南。

延伸閱讀

Guide一次過攞歷史外匯時間序列閱讀 Reference點讀 source 同 market_session閱讀 Guide指示性匯率同可執行匯率閱讀
更多比較Fixer vs exchangerate.devOpen Exchange Rates vs exchangerate.devCurrencylayer vs exchangerate.dev
學習Reading source and market_session in your pipelineIndicative vs executable FX rates: what a rates API actually gives youECB reference rates, explained
即時匯率EUR/USDGBP/USDUSD/JPY