HttpClient es la API de .NET para enviar peticiones HTTP y recibir respuestas de servicios remotos.
En Interactive WebAssembly, el código se ejecuta dentro del navegador y necesita una API para acceder a datos del servidor. En SSR o Interactive Server, HttpClient también permite llamar a servicios HTTP internos o externos.
En el servidor debemos gestionar correctamente la reutilización de sus conexiones. En WebAssembly, HttpClient se apoya en la API fetch del navegador.
El problema de new HttpClient()
Instintivamente, podríamos pensar en hacer esto dentro de un servicio:
// ⛔ MAL: No hagas esto en producción
using (var client = new HttpClient())
{
var response = await client.GetAsync("https://miapi.com/productos");
}En .NET del lado servidor, crear y destruir clientes por petición impide reutilizar correctamente los manejadores y puede provocar agotamiento de puertos o problemas al actualizar DNS.
Para solucionar esto, Microsoft introdujo IHttpClientFactory.
Esta fábrica reutiliza y rota manejadores HTTP, además de permitir configurar clientes de forma centralizada. Para usarla en un proyecto cliente Blazor, añade el paquete Microsoft.Extensions.Http.
Configurar clientes tipados
Una opción cómoda es usar clientes tipados, que encapsulan las llamadas de una API concreta.
Esto vincula una configuración HTTP específica (URL base, cabeceras) a una clase de servicio concreta.
Registro en Program.cs
En lugar de registrar el servicio con AddScoped a secas, usamos AddHttpClient.
// Program.cs
// Registramos el servicio Y configuramos su HttpClient asociado
builder.Services.AddHttpClient<IProductoService, ProductoServiceAPI>(client =>
{
// Configuramos la URL base. Así el servicio no necesita saber la IP del servidor.
client.BaseAddress = new Uri("https://api.luisllamas.es/v1/");
// Podemos añadir cabeceras globales (ej: API Key, User-Agent)
client.DefaultRequestHeaders.Add("Accept", "application/json");
});Inyección en el servicio
Ahora, en nuestra clase ProductoServiceAPI, inyectamos HttpClient por el constructor.
La instancia recibida ya contiene la BaseAddress y los encabezados configurados en Program.cs.
public class ProductoServiceAPI : IProductoService
{
private readonly HttpClient _http;
public ProductoServiceAPI(HttpClient http)
{
_http = http;
}
// Métodos de implementación...
}Extensiones JSON (System.Net.Http.Json)
Antiguamente, leer un objeto desde una API era un proceso de tres pasos:
client.GetAsync(...)response.Content.ReadAsStringAsync()JsonSerializer.Deserialize<T>(json)
En .NET moderno, tenemos métodos de extensión que hacen todo esto en una sola línea y de forma optimizada.
GET: Obtener datos
public async Task<List<ProductoDto>> GetProductosAsync()
{
// Hace el GET a "https://api.luisllamas.es/v1/productos"
// Deserializa el JSON automáticamente a List<ProductoDto>
// Si la respuesta no es satisfactoria, lanza HttpRequestException
return await _http.GetFromJsonAsync<List<ProductoDto>>("productos")
?? new List<ProductoDto>();
}POST: Enviar datos
public async Task CrearProductoAsync(ProductoDto nuevoProducto)
{
// Serializa el objeto a JSON y lo envía por POST
var respuesta = await _http.PostAsJsonAsync("productos", nuevoProducto);
if (!respuesta.IsSuccessStatusCode)
{
// Manejar el error
var error = await respuesta.Content.ReadAsStringAsync();
throw new Exception($"Error al crear: {error}");
}
}Los métodos GetFromJsonAsync, PostAsJsonAsync y PutAsJsonAsync se encuentran en el namespace System.Net.Http.Json. Asegúrate de tener el using correspondiente.
Diferencias: Server vs WebAssembly
Es importante entender que, aunque el código C# es idéntico, lo que ocurre “por debajo” es diferente:
- En Blazor Server: El
HttpClientcorre en el servidor. Puede acceder a otras APIs internas de tu red (microservicios) sin problemas de CORS. - En Blazor WebAssembly: El
HttpClientes solo un envoltorio sobre la APIfetchdel navegador.
- Estás limitado por las reglas de seguridad del navegador (Same-Origin Policy).
- Si tu API está en otro dominio, debes configurar CORS (Cross-Origin Resource Sharing) en el servidor de la API para permitir las peticiones.