Tutorial/C# y .NET

Tipos de cambio en C# y .NET

Crea un cliente FX tipado con IHttpClientFactory, valores decimal, cancelación, tiempo límite y manejo consciente de la fuente.

MMexchangerate.dev·Jul 17, 2026·6 min de lectura

Registra un HttpClient tipado para exchangerate.dev, inyecta la clave desde la configuración y convierte los tipos a decimal. Propaga la cancelación y limita el tiempo de la llamada.

Key points
Usa IHttpClientFactory para configurar y reutilizar conexiones.
Convierte los tipos a decimal.
Propaga CancellationToken y define un tiempo límite.
Ejecuta EnsureSuccessStatusCode() antes de decodificar.

Registra un HttpClient tipado

El registro define URL, token y tiempo límite. El cliente tipado conserva el contrato de respuesta y pasa la cancelación a la solicitud.

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");
    }
}

Propaga la cancelación desde la solicitud

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();

Almacena solo observaciones correctas

Una caché compartida debe guardar la observación completa, no solo Rates["EUR"]. Conserva Source, MarketSession y DataUpdatedAt para interpretar el valor.

Los reintentos requieren una política estrecha
Reintenta fallos breves de red o determinados 5xx con una pausa pequeña. No trates un 401 como transitorio ni generes una ráfaga tras un 429.
  • Mantén un único registro de cliente tipado.
  • Usa decimal para tipos y montos.
  • Propaga la cancelación.
  • Rechaza errores HTTP antes de decodificar.
MM
exchangerate.dev
Guías de integración para desarrolladores que trabajan con datos FX.

Keep reading

GuideSeries históricas FX en una llamadaRead ReferenceCómo leer source y market_sessionRead GuideTipos FX indicativos y ejecutablesRead