为 exchangerate.dev 注册一个带类型的 HttpClient,从配置注入 API 密钥,并将汇率反序列化为 decimal。传递取消令牌并设置有限超时,避免上游慢请求长期占用应用请求。
要点
使用
IHttpClientFactory 统一管理连接与客户端配置。把汇率反序列化为
decimal 并保留新鲜度字段。传递
CancellationToken 并设置超时。解码前调用
EnsureSuccessStatusCode()。注册带类型的 HttpClient
注册配置基础 URL、bearer token 与超时。带类型的客户端负责响应契约,并把调用方的取消传给网络请求。
// 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");
}
}从请求传递取消令牌
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"]。保留 Source、MarketSession 与 DataUpdatedAt,调用方才能区分实时交易日更新、每日参考值与闭市值。
重试策略必须收窄
短暂网络故障或部分 5xx 可以小幅退避后重试。不要把 401 当成短暂故障,也不要在 429 后制造重试风暴。应先通过缓存和请求合并消除重复流量。
- 保留一个带类型的客户端注册。
- 汇率与金额使用 decimal。
- 在完整调用链中传递取消。
- 反序列化前拒绝非成功响应。
ER
exchangerate.dev
面向使用外汇数据的开发者的集成指南。
