Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Nota
Esta no es la versión más reciente de este artículo. Para la versión actual, consulte la versión de .NET 9 de este artículo.
Advertencia
Esta versión de ASP.NET Core ya no se admite. Para obtener más información, consulte la Política de Soporte de .NET y .NET Core. Para la versión actual, consulte la versión de .NET 9 de este artículo.
Importante
Esta información hace referencia a un producto en versión preliminar, el cual puede sufrir importantes modificaciones antes de que se publique la versión comercial. Microsoft no proporciona ninguna garantía, expresa o implícita, con respecto a la información proporcionada aquí.
Para la versión actual, consulte la versión de .NET 9 de este artículo.
En este artículo se describe cómo llamar a una API web desde una aplicación Blazor.
Paquete
El paquete System.Net.Http.Json
proporciona métodos de extensión para System.Net.Http.HttpClient y System.Net.Http.HttpContent que realizan automáticamente la serialización y deserialización mediante System.Text.Json
. El marco compartido de .NET proporciona el paquete System.Net.Http.Json
y no requiere que se agregue una referencia de paquete a la aplicación.
Uso de un controlador de tokens para llamadas API web
Blazor Web Apps con la autenticación de OIDC pueden usar un enfoque de controlador de tokens para realizar solicitudes salientes y asegurar las llamadas a APIs web externas. Las aplicaciones de ejemplo BlazorWebAppOidc
y BlazorWebAppOidcServer
que se describen en la sección Aplicaciones de ejemplo de este artículo usan este enfoque.
Para obtener más información, consulta los siguientes recursos:
- ASP.NET Core del lado del servidor y Blazor Web App escenarios de seguridad adicionales
- Protección de un ASP.NET Core Blazor Web App con OpenID Connect (OIDC)
Plataforma de identidad de Microsoft para llamadas API web
Blazor Web Appaquellos que utilizan la plataforma de identidad de Microsoft con paquetes web de Microsoft Identity para Microsoft Entra ID pueden hacer llamadas simplificadas a la API web con la API proporcionada por el Microsoft.Identity.Web.DownstreamApi
paquete NuGet.
Nota
Para obtener instrucciones sobre cómo agregar paquetes a aplicaciones .NET, consulte los artículos en Instalación y administración de paquetes en el flujo de trabajo de consumo de paquetes (documentación de NuGet). Confirme las versiones correctas del paquete en NuGet.org.
En el archivo de configuración de la aplicación (appsettings.json
), proporcione una dirección URL base y ámbitos. En el ejemplo siguiente, el {BASE ADDRESS}
marcador de posición es la dirección URL base de la API web. Se especifica un único ámbito con un URI de ID de aplicación ({APP ID URI}
elemento de marcador de posición) y un nombre de ámbito ({SCOPE NAME}
elemento de marcador de posición):
"DownstreamApi": {
"BaseUrl": "{BASE ADDRESS}",
"Scopes": [ "{APP ID URI}/{SCOPE NAME}" ]
}
Ejemplo:
"DownstreamApi": {
"BaseUrl": "https://localhost:7277",
"Scopes": [ "api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get" ]
}
En el archivo de la aplicación Program
, llame a:
- EnableTokenAcquisitionToCallDownstreamApi: habilita la adquisición de tokens para que se puedan llamar a las API web.
-
AddDownstreamApi
: Los paquetes web de Microsoft Identity proporcionan una API para crear un servicio web descendente con nombre para realizar llamadas a API web. IDownstreamApi se inserta en una clase del lado del servidor, que se utiliza para llamar a CallApiForUserAsync y obtener datos meteorológicos de una API web externa (proyectoMinimalApiJwt
). - AddDistributedTokenCaches: agrega las memorias caché de tokens distribuidos de .NET Core a la colección de servicios.
- AddDistributedMemoryCache: agrega una implementación predeterminada de IDistributedCache que almacena los elementos de caché en la memoria.
- Configure las opciones de caché de tokens distribuidos (MsalDistributedTokenCacheAdapterOptions):
- En el desarrollo con fines de depuración, puede deshabilitar la memoria caché L1 configurando DisableL1Cache a
true
. Asegúrese de restablecerlo afalse
para producción. - Establezca el tamaño máximo de la memoria caché L1 con
L1CacheOptions.SizeLimit
para evitar que la memoria caché sobrerute la memoria del servidor. El valor predeterminado es 500 MB. - Durante el desarrollo para fines de depuración, puede deshabilitar el cifrado de tokens en reposo estableciendo Encrypt a
false
, que es el valor predeterminado. Asegúrese de restablecerlo atrue
para producción. - Establezca la expulsión de tokens de la memoria caché con SlidingExpiration. El valor predeterminado es 1 hora.
- Para obtener más información, incluidas las instrucciones sobre la devolución de llamada para errores de caché L2 (OnL2CacheFailure) y escrituras asincrónicas de caché L2 (EnableAsyncL2Write), consulte MsalDistributedTokenCacheAdapterOptions y Serialización de cachés de tokens: cachés de tokens distribuidos.
- En el desarrollo con fines de depuración, puede deshabilitar la memoria caché L1 configurando DisableL1Cache a
Puede optar por cifrar la memoria caché y siempre debe hacerlo en producción.
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()
.AddDownstreamApi("DownstreamApi",
builder.Configuration.GetSection("DownstreamApi"))
.AddDistributedTokenCaches();
// Requires the 'Microsoft.Extensions.Caching.Memory' NuGet package
builder.Services.AddDistributedMemoryCache();
builder.Services.Configure<MsalDistributedTokenCacheAdapterOptions>(
options =>
{
// The following lines that are commented out reflect
// default values. We recommend overriding the default
// value of Encrypt to encrypt tokens at rest.
//options.DisableL1Cache = false;
//options.L1CacheOptions.SizeLimit = 500 * 1024 * 1024;
options.Encrypt = true;
//options.SlidingExpiration = TimeSpan.FromHours(1);
});
Las memorias caché de tokens distribuidos en memoria se crean al llamar a AddDistributedTokenCaches para garantizar que exista una implementación base disponible para el almacenamiento en caché de tokens distribuidos.
Las aplicaciones web de producción y las API web deben usar una caché de tokens distribuidos de producción (por ejemplo: Redis, Microsoft SQL Server, Microsoft Azure Cosmos DB).
Nota
Para el desarrollo y las pruebas locales en una sola máquina, puede usar cachés de tokens en memoria en lugar de cachés de tokens distribuidos:
builder.Services.AddInMemoryTokenCaches();
Más adelante en el período de desarrollo y pruebas, adopte un proveedor de caché de tokens distribuidos de producción.
AddDistributedMemoryCache agrega una implementación predeterminada de IDistributedCache que almacena los elementos de caché en memoria, que es utilizada por Microsoft Identity Web para el almacenamiento en caché de tokens.
AddDistributedMemoryCache requiere una referencia de paquete al Microsoft.Extensions.Caching.Memory
paquete NuGet.
Nota
Para obtener instrucciones sobre cómo agregar paquetes a aplicaciones .NET, consulte los artículos en Instalación y administración de paquetes en el flujo de trabajo de consumo de paquetes (documentación de NuGet). Confirme las versiones correctas del paquete en NuGet.org.
Para configurar un proveedor de caché distribuida de producción, consulte Almacenamiento en caché distribuido en ASP.NET Core.
Advertencia
Reemplace siempre las memorias caché de tokens distribuidos en memoria por un proveedor de caché de tokens real al implementar la aplicación en un entorno de producción. Si no adopta un proveedor de caché de tokens distribuidos de producción, la aplicación puede sufrir un rendimiento significativamente degradado.
Para obtener más información, consulte Serialización de caché de tokens: cachés distribuidas. Sin embargo, los ejemplos de código que se muestran no se aplican a aplicaciones de ASP.NET Core, que configuran cachés distribuidas a través de AddDistributedMemoryCache, no AddDistributedTokenCache.
Use un anillo compartido de claves de protección de datos en producción para que las instancias de la aplicación a través de servidores de una granja web puedan descifrar tokens cuando MsalDistributedTokenCacheAdapterOptions.Encrypt se establece en true
.
Nota
Para el desarrollo temprano y las pruebas locales en una sola máquina, puede establecer Encrypt a false
y configurar un anillo compartido de claves de protección de datos más adelante:
options.Encrypt = false;
Más adelante en el período de desarrollo y pruebas, habilite el cifrado de tokens y adopte un anillo de claves de protección de datos compartido.
En el ejemplo siguiente se muestra cómo usar Azure Blob Storage y Azure Key Vault (PersistKeysToAzureBlobStorage
/ProtectKeysWithAzureKeyVault
) para el anillo de claves compartido. Las configuraciones de servicio son escenarios de casos base con fines de demostración. Antes de implementar aplicaciones de producción, familiarícese con los servicios de Azure y adopte procedimientos recomendados mediante sus conjuntos de documentación dedicados, que se enumeran al final de esta sección.
Agregue los siguientes paquetes al proyecto de servidor de Blazor Web App:
Nota
Para obtener instrucciones sobre cómo agregar paquetes a aplicaciones .NET, consulte los artículos en Instalación y administración de paquetes en el flujo de trabajo de consumo de paquetes (documentación de NuGet). Confirme las versiones correctas del paquete en NuGet.org.
Nota
Antes de continuar con los pasos siguientes, confirme que la aplicación está registrada con Microsoft Entra.
Configure Azure Blob Storage para mantener las claves de protección de datos y cifrarlas en reposo con Azure Key Vault:
Cree una cuenta de almacenamiento de Azure. El nombre de la cuenta en el ejemplo siguiente es
contoso
.Cree un contenedor para contener las claves de protección de datos. El nombre del contenedor en el ejemplo siguiente es
data-protection
.Cree el archivo de clave en el equipo local. En el ejemplo siguiente, el archivo de clave se denomina
keys.xml
. Puede usar un editor de texto para crear el archivo.keys.xml
:<?xml version="1.0" encoding="utf-8"?> <repository> </repository>
Cargue el archivo de clave (
keys.xml
) en el contenedor de la cuenta de almacenamiento. Use el comando View/edit del menú contextual al final de la fila de claves del portal para confirmar que el blob contiene el contenido anterior.Use el comando Generar SAS del menú contextual para obtener el URI del blob con una firma de acceso compartido (SAS). Al crear la SAS, use los siguientes permisos:
Read
,Add
,Create
,Write
, .Delete
El URI se usa más adelante donde aparece el{BLOB URI WITH SAS}
marcador de posición.
Al establecer el almacén de claves en el Portal de Azure o Azure Active Directory:
Configure el almacén de claves para usar una política de acceso al almacén. Confirme que el acceso público en el paso Redes está habilitado (activado).
En el panel Directivas de acceso, cree una nueva directiva de acceso con permisos de clave
Get
,Unwrap Key
yWrap Key
. Seleccione la aplicación registrada como principal de servicio.Cuando el cifrado de claves está activo, las claves del archivo de claves incluyen el comentario "This key is encrypted with Azure Key Vault." Después de iniciar la aplicación, seleccione el comando Ver o editar en el menú contextual al final de la fila de claves para confirmar que una clave está presente con la seguridad del almacén de claves aplicada.
El AzureEventSourceLogForwarder servicio del ejemplo siguiente reenvía los mensajes de registro del SDK de Azure para el registro y requiere el Microsoft.Extensions.Azure
paquete NuGet.
Nota
Para obtener instrucciones sobre cómo agregar paquetes a aplicaciones .NET, consulte los artículos en Instalación y administración de paquetes en el flujo de trabajo de consumo de paquetes (documentación de NuGet). Confirme las versiones correctas del paquete en NuGet.org.
En la parte superior del archivo Program
, proporcione acceso a la API en el espacio de nombres Microsoft.Extensions.Azure.
using Microsoft.Extensions.Azure;
Use el código siguiente en el Program
archivo donde se registran los servicios:
builder.Services.TryAddSingleton<AzureEventSourceLogForwarder>();
builder.Services.AddDataProtection()
.PersistKeysToAzureBlobStorage(new Uri("{BLOB URI WITH SAS}"))
.ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), new DefaultAzureCredential());
{BLOB URI WITH SAS}
: el URI completo donde se debe almacenar el archivo de clave con el token de SAS como parámetro de cadena de consulta. Azure Storage genera el URI cuando solicita una SAS para el archivo de clave cargado. El nombre del contenedor en el ejemplo siguiente es data-protection
y el nombre de la cuenta de almacenamiento es contoso
. El archivo de clave se denomina keys.xml
.
Ejemplo:
https://contoso.blob.core.windows.net/data-protection/keys.xml?sp={PERMISSIONS}&st={START DATETIME}&se={EXPIRATION DATETIME}&spr=https&sv={STORAGE VERSION DATE}&sr=c&sig={TOKEN}
{KEY IDENTIFIER}
: identificador de clave de Azure Key Vault que se usa para el cifrado de claves. El nombre del almacén de claves es contoso
en el ejemplo siguiente, y una directiva de acceso permite a la aplicación acceder al almacén de claves con permisos de Get
, Unwrap Key
, y Wrap Key
. El nombre de clave de ejemplo es data-protection
. La versión de la clave ({KEY VERSION}
marcador de posición) se obtiene de la clave en Entra o Azure Portal después de crearla.
Ejemplo:
https://contoso.vault.azure.net/keys/data-protection/{KEY VERSION}
Inserte IDownstreamApi y llame a CallApiForUserAsync cuando actúe en nombre de un usuario.
internal sealed class ServerWeatherForecaster(IDownstreamApi downstreamApi) : IWeatherForecaster
{
public async Task<IEnumerable<WeatherForecast>> GetWeatherForecastAsync()
{
var response = await downstreamApi.CallApiForUserAsync("DownstreamApi",
options =>
{
options.RelativePath = "/weather-forecast";
});
return await response.Content.ReadFromJsonAsync<WeatherForecast[]>() ??
throw new IOException("No weather forecast!");
}
}
Las aplicaciones de ejemplo BlazorWebAppEntra
y BlazorWebAppEntraBff
que se describen en la sección Aplicaciones de ejemplo de este artículo usan este enfoque.
Para obtener más información, consulta los siguientes recursos:
- Documentación de la API web | Plataforma de identidad de Microsoft
- Una API web que llama a las API web: Llamada a una API: Opción 2: Llamada a una API web de bajada con la clase auxiliar
- IDownstreamApi
- Protección de una Blazor Web App de ASP.NET Core con Microsoft Entra ID
- Hospedar ASP.NET Core en una granja de servidores web: Protección de datos
- Configuración de la protección de datos principal de ASP.NET
- Proveedores de almacenamiento de claves en ASP.NET Core
- Documentación de Azure Key Vault
- Documentación de Azure Storage
Aplicaciones de muestra
Para ver ejemplos de trabajo, consulte las siguientes aplicaciones de ejemplo en el Blazor repositorio de GitHub de ejemplos () (dotnet/blazor-samples
cómo descargar).
BlazorWebAppCallWebApi
Llamar a una API web de lista de tareas externa (no en el Blazor Web App) desde un Blazor Web App:
-
Backend
: una aplicación de API web para mantener una lista de tareas pendientes, en función de las API mínimas. La aplicación de API web es una aplicación independiente de la Blazor Web App, posiblemente hospedada en otro servidor. -
BlazorApp
/BlazorApp.Client
: una Blazor Web App que llama a la aplicación de API web con un HttpClient para las operaciones de lista de tareas pendientes, como crear, leer, actualizar y eliminar elementos (CRUD) de la lista de tareas pendientes.
Para la representación del lado cliente (CSR), que incluye componentes interactivos de WebAssembly y componentes automáticos que han adoptado CSR, las llamadas se realizan con un HttpClient preconfigurado registrado en el archivo Program
del proyecto de cliente (BlazorApp.Client
):
builder.Services.AddScoped(sp =>
new HttpClient
{
BaseAddress = new Uri(builder.Configuration["FrontendUrl"] ??
"https://localhost:5002")
});
En el caso de la representación del lado servidor (SSR), que incluye componentes de servidor prerenderizados e interactivos, componentes de WebAssembly prerenderizados y componentes automáticos que son prerenderizados o han adoptado SSR, las llamadas se realizan con un HttpClient registrado en el archivo Program
del proyecto del servidor (BlazorApp
):
builder.Services.AddHttpClient();
Llama a una API interna de lista de películas (dentro de la Blazor Web App), donde la API reside en el proyecto de servidor de la Blazor Web App:
-
BlazorApp
: una Blazor Web App que mantiene una lista de películas:- Cuando se realizan operaciones en la lista de películas dentro de la aplicación en el servidor, se usan llamadas API normales.
- Cuando un cliente basado en web realiza llamadas API, se usa una API web para las operaciones de lista de películas, en función de las API mínimas.
-
BlazorApp.Client
: el proyecto de cliente de la Blazor Web App, que contiene componentes interactivos de WebAssembly y Auto para la administración de usuarios de la lista de películas.
Para CSR, que incluye componentes interactivos de WebAssembly y componentes automáticos que han adoptado CSR, las llamadas a la API se realizan a través de un servicio basado en cliente (ClientMovieService
) que usa un HttpClient preconfigurado registrado en el archivo Program
del proyecto de cliente (BlazorApp.Client
). Dado que estas llamadas se realizan a través de una web pública o privada, la API de lista de películas es una API web.
En el ejemplo siguiente se obtiene una lista de películas del endpoint /movies
.
public class ClientMovieService(HttpClient http) : IMovieService
{
public async Task<Movie[]> GetMoviesAsync(bool watchedMovies) =>
await http.GetFromJsonAsync<Movie[]>("movies") ?? [];
}
En el caso de SSR, que incluye componentes de servidor representados previamente e interactivos, componentes WebAssembly representados previamente y componentes automáticos representados previamente o que han adoptado SSR, las llamadas se realizan directamente a través de un servicio basado en servidor (ServerMovieService
). La API no se basa en una red, por lo que es una API estándar para las operaciones CRUD de lista de películas.
En el ejemplo siguiente se obtiene una lista de películas:
public class ServerMovieService(MovieContext db) : IMovieService
{
public async Task<Movie[]> GetMoviesAsync(bool watchedMovies) =>
watchedMovies ?
await db.Movies.Where(t => t.IsWatched).ToArrayAsync() :
await db.Movies.ToArrayAsync();
}
Para obtener más información sobre cómo proteger los datos de películas en este escenario, consulte el ejemplo de datos meteorológicos descrito en Protección de datos en Blazor Web Apps con renderizado automático interactivo.
BlazorWebAppCallWebApi_Weather
Una aplicación de ejemplo de datos meteorológicos que usa la representación de streaming para los datos meteorológicos.
BlazorWebAssemblyCallWebApi
Llama a una API web de lista de tareas pendientes desde una aplicación de Blazor WebAssembly :
-
Backend
: una aplicación de API web para mantener una lista de tareas pendientes, en función de las API mínimas. -
BlazorTodo
: una aplicación de Blazor WebAssembly que llama a la API web con un HttpClient preconfigurado para las operaciones CRUD de lista de tareas pendientes.
BlazorWebAssemblyStandaloneWithIdentity
Una aplicación independiente Blazor WebAssembly protegida con ASP.NET Core Identity:
-
Backend
: una aplicación de API web de back-end que mantiene un almacén de identidades de usuario para ASP.NET Core Identity. -
BlazorWasmAuth
: una aplicación de front-end Blazor WebAssembly independiente con autenticación de usuario.
La solución muestra cómo llamar a una API web segura para lo siguiente:
- Obtener los roles de un usuario autenticado.
- Procesamiento de datos para todos los usuarios autenticados.
- Procesamiento de datos para usuarios autorizados (el usuario debe estar en el
Manager
rol) a través de una directiva de autorización.
BlazorWebAppOidc
Una interactividad automática global con Blazor Web App que utiliza la autenticación de OIDC con Microsoft Entra sin usar paquetes específicos de Entra. En el ejemplo se muestra cómo usar un controlador de tokens para las llamadas API web para llamar a una API web segura externa.
BlazorWebAppOidcServer
Una interactividad global del Interactive Server que utiliza autenticación OIDC con Microsoft Entra sin emplear paquetes específicos de Entra. En el ejemplo se muestra cómo pasar un token de acceso para llamar a una API web segura externa.
BlazorWebAppOidcBff
Una interactividad automática global con Blazor Web App que usa:
- Autenticación OIDC con Microsoft Entra sin usar paquetes específicos de Entra.
- El patrón Backend for Frontend (BFF), que es un patrón de desarrollo de aplicaciones que crea servicios posteriores para aplicaciones o interfaces frontales.
La solución incluye una demostración de cómo obtener datos meteorológicos de forma segura a través de una API web externa cuando un componente que adopta la representación automática interactiva se representa en el cliente.
BlazorWebAppEntra
Interactividad global de Auto con Blazor Web App que utiliza la plataforma de identidad de Microsoft con paquetes web de Microsoft Identity para Microsoft Entra ID. La solución incluye una demostración de cómo obtener datos meteorológicos de forma segura a través de una API web externa cuando un componente que adopta la representación automática interactiva se representa en el cliente.
BlazorWebAppEntraBff
Una interactividad automática global con Blazor Web App que usa:
- Plataforma de identidad de Microsoft con paquetes web de Microsoft Identity para el identificador de Entra de Microsoft.
- El patrón Backend for Frontend (BFF), que es un patrón de desarrollo de aplicaciones que crea servicios posteriores para aplicaciones o interfaces frontales.
La solución incluye una demostración de cómo obtener datos meteorológicos de forma segura a través de una API web externa cuando un componente que adopta la representación automática interactiva se representa en el cliente.
Eliminación de HttpRequestMessage
, HttpResponseMessage
y HttpClient
Un HttpRequestMessage sin cuerpo no requiere eliminación explícita con una using
declaración (C# 8 o posterior) o un using
bloque (todas las versiones de C#), pero se recomienda eliminar con cada uso por los siguientes motivos:
- Para obtener una mejora en el rendimiento evitando los finalizadores.
- Fortalece el código para el futuro en caso de que alguna vez se agregue un cuerpo de solicitud a un HttpRequestMessage que inicialmente no tenía uno.
- Para evitar potencialmente problemas funcionales si un controlador de delegación espera una llamada a Dispose/DisposeAsync.
- Es más sencillo aplicar una regla general en todas partes que intentar recordar casos específicos.
Elimine siempre las HttpResponseMessage instancias.
Nunca elimine HttpClient las instancias creadas mediante una llamada a CreateClient porque están administradas por el marco.
Ejemplo:
using var request = new HttpRequestMessage(HttpMethod.Get, "/weather-forecast");
var client = clientFactory.CreateClient("ExternalApi");
using var response = await client.SendAsync(request);
Escenarios del lado cliente para llamar a API web externas
Los componentes basados en cliente llaman a APIs web externas usando instancias de HttpClient, que normalmente se crean con un HttpClient preconfigurado registrado en el archivo Program
:
builder.Services.AddScoped(sp =>
new HttpClient
{
BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
});
El siguiente Razor componente realiza una solicitud a una API web para ramas de GitHub similares al ejemplo de uso básico en el artículo Realización de solicitudes HTTP mediante IHttpClientFactory en ASP.NET Core .
CallWebAPI.razor
:
@page "/call-web-api"
@using System.Text.Json
@using System.Text.Json.Serialization
@inject HttpClient Client
<h1>Call web API from a Blazor WebAssembly Razor component</h1>
@if (getBranchesError || branches is null)
{
<p>Unable to get branches from GitHub. Please try again later.</p>
}
else
{
<ul>
@foreach (var branch in branches)
{
<li>@branch.Name</li>
}
</ul>
}
@code {
private IEnumerable<GitHubBranch>? branches = [];
private bool getBranchesError;
private bool shouldRender;
protected override bool ShouldRender() => shouldRender;
protected override async Task OnInitializedAsync()
{
using var request = new HttpRequestMessage(HttpMethod.Get,
"https://api.github.com/repos/dotnet/AspNetCore.Docs/branches");
request.Headers.Add("Accept", "application/vnd.github.v3+json");
request.Headers.Add("User-Agent", "HttpClientFactory-Sample");
using var response = await Client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
using var responseStream = await response.Content.ReadAsStreamAsync();
branches = await JsonSerializer.DeserializeAsync
<IEnumerable<GitHubBranch>>(responseStream);
}
else
{
getBranchesError = true;
}
shouldRender = true;
}
public class GitHubBranch
{
[JsonPropertyName("name")]
public string? Name { get; set; }
}
}
En el ejemplo anterior de C# 12 o posterior, se crea una matriz vacía ([]
) para la variable branches
. Para versiones anteriores de C# compiladas con un SDK anterior a .NET 8, cree una matriz vacía (Array.Empty<GitHubBranch>()
).
Para proteger el código y los datos de .NET/C#, use las características de Protección de Datos de ASP.NET Core con una API web del lado del servidor ASP.NET Core. La aplicación Blazor WebAssembly del lado cliente llama a la API web del lado servidor para proteger las características de la aplicación y el procesamiento de datos.
Blazor WebAssembly A menudo se impide que las aplicaciones realicen llamadas directas entre orígenes a las API web debido a la seguridad CORS (Compartición de Recursos entre Orígenes). Una excepción típica es similar a la siguiente:
El acceso a la obtención en '{URL}' desde el origen 'https://localhost:{PORT}' ha sido bloqueado por la directiva de CORS: no hay encabezado 'Access-Control-Allow-Origin' presente en el recurso solicitado. Si una respuesta opaca satisface sus necesidades, establezca el modo de la solicitud en 'no-cors' para obtener el recurso con CORS deshabilitado.
Incluso si llama a SetBrowserRequestMode con un campo BrowserRequestMode de NoCors
(1) que busca eludir la excepción anterior, la solicitud suele fallar debido a las restricciones de CORS en el origen de la API web, como una restricción que solo permite llamadas desde orígenes específicos o una restricción que impide las solicitudes JavaScript fetch
desde un navegador. La única manera de que estas llamadas se realicen correctamente es que la API web que estás llamando permita que tu origen llame a su propio origen con la configuración de CORS correcta. La mayoría de las API web externas no permiten configurar sus directivas de CORS. Para tratar esta restricción, adopte cualquiera de las siguientes estrategias:
Mantenga su propia API web de back-end del lado servidor de ASP.NET Core. La aplicación del lado cliente Blazor WebAssembly llama a la API web del lado servidor y la API web realiza la solicitud desde su código de C# basado en servidor (no un explorador) a la API web externa con los encabezados CORS correctos, devolviendo el resultado a la aplicación de Blazor WebAssembly del lado cliente.
Usar un servicio de proxy para reenviar la solicitud de la aplicación Blazor WebAssembly del lado cliente a la API web externa. El servicio proxy usa una aplicación del lado servidor para realizar la solicitud en nombre del cliente y devuelve el resultado después de que la llamada se realice correctamente. En el siguiente ejemplo basado en el proxy CORS de CloudFlare , el marcador de posición
{REQUEST URI}
es el URI de solicitud.@using System.Net @inject IHttpClientFactory ClientFactory ... @code { public async Task CallApi() { var client = ClientFactory.CreateClient(); var urlEncodedRequestUri = WebUtility.UrlEncode("{REQUEST URI}"); using var request = new HttpRequestMessage(HttpMethod.Get, $"https://corsproxy.io/?{urlEncodedRequestUri}"); using var response = await client.SendAsync(request); ... } }
Escenarios del lado servidor para llamar a API web externas
Los componentes basados en servidor llaman a las API web externas usando instancias de HttpClient, normalmente creadas usando IHttpClientFactory. Para obtener instrucciones que se aplican a las aplicaciones del lado servidor, consulte Realización de solicitudes HTTP con IHttpClientFactory en ASP.NET Core.
Una aplicación de servidor no incluye un servicio HttpClient. Proporcione un HttpClient a la aplicación usando la infraestructura de fábrica de HttpClient
.
En el archivo Program
:
builder.Services.AddHttpClient();
El siguiente Razor componente realiza una solicitud a una API web para ramas de GitHub similares al ejemplo de uso básico en el artículo Realización de solicitudes HTTP mediante IHttpClientFactory en ASP.NET Core .
CallWebAPI.razor
:
@page "/call-web-api"
@using System.Text.Json
@using System.Text.Json.Serialization
@inject IHttpClientFactory ClientFactory
<h1>Call web API from a server-side Razor component</h1>
@if (getBranchesError || branches is null)
{
<p>Unable to get branches from GitHub. Please try again later.</p>
}
else
{
<ul>
@foreach (var branch in branches)
{
<li>@branch.Name</li>
}
</ul>
}
@code {
private IEnumerable<GitHubBranch>? branches = [];
private bool getBranchesError;
private bool shouldRender;
protected override bool ShouldRender() => shouldRender;
protected override async Task OnInitializedAsync()
{
using var request = new HttpRequestMessage(HttpMethod.Get,
"https://api.github.com/repos/dotnet/AspNetCore.Docs/branches");
request.Headers.Add("Accept", "application/vnd.github.v3+json");
request.Headers.Add("User-Agent", "HttpClientFactory-Sample");
var client = ClientFactory.CreateClient();
using var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
using var responseStream = await response.Content.ReadAsStreamAsync();
branches = await JsonSerializer.DeserializeAsync
<IEnumerable<GitHubBranch>>(responseStream);
}
else
{
getBranchesError = true;
}
shouldRender = true;
}
public class GitHubBranch
{
[JsonPropertyName("name")]
public string? Name { get; set; }
}
}
En el ejemplo anterior de C# 12 o posterior, se crea una matriz vacía ([]
) para la variable branches
. Para versiones anteriores de C# compiladas con un SDK anterior a .NET 8, cree una matriz vacía (Array.Empty<GitHubBranch>()
).
Para obtener un ejemplo de trabajo adicional, consulte el ejemplo de carga de archivos del lado servidor que carga archivos en un controlador de API web en el artículo sobre cargas de archivos de ASP.NET CoreBlazor.
Abstracciones de servicio para llamadas API web
Esta sección se aplica a Blazor Web Apps que mantienen una API web en el proyecto de servidor o transforman llamadas API web a una API web externa.
Al usar los modos de representación interactiva de WebAssembly y Auto, los componentes se prerenderizan por defecto. Los componentes automáticos también se representan inicialmente de forma interactiva desde el servidor antes de que la agrupación de Blazor se descargue en el cliente y el entorno de ejecución del lado cliente se active. Esto significa que los componentes que usan estos modos de representación deben diseñarse para que se ejecuten correctamente desde el cliente y el servidor. Si el componente debe llamar a una API basada en proyectos de servidor o transformar una solicitud a una API web externa (una que está fuera de la Blazor Web App) al ejecutarse en el cliente, el enfoque recomendado es abstraer esa llamada API detrás de una interfaz de servicio e implementar versiones de cliente y servidor del servicio:
- La versión del cliente llama a la API web con un HttpClient preconfigurado.
- Normalmente, la versión del servidor puede acceder directamente a los recursos del lado servidor. La inserción de un HttpClient en el servidor que realiza llamadas de vuelta al servidor no se recomienda, ya que la solicitud de red suele ser innecesaria. Como alternativa, la API podría ser externa al proyecto de servidor, pero se requiere una abstracción de servicio para el servidor para transformar la solicitud de alguna manera, por ejemplo, para agregar un token de acceso a una solicitud proxy.
Al usar el modo de representación de WebAssembly, también tienes la opción de deshabilitar la representación previa, por lo que los componentes solo se representan desde el cliente. Para obtener más información, consulte modos de representación de ASP.NET CoreBlazor.
Ejemplos (aplicaciones de ejemplo):
- API web de lista de películas en la aplicación de ejemplo de
BlazorWebAppCallWebApi
. - Streaming que representa los datos meteorológicos de la API web en la aplicación de
BlazorWebAppCallWebApi_Weather
muestra. - Los datos meteorológicos se devuelven al cliente en las aplicaciones de ejemplo utilizando el
BlazorWebAppOidc
(patrón no BFF) o elBlazorWebAppOidcBff
(patrón BFF). Estas aplicaciones muestran llamadas API seguras (web). Para obtener más información, consulta Blazor Web App.
API web externas de Blazor Web App
Blazor Web App
Las Blazor Web App normalmente representan los componentes de WebAssembly del lado cliente y los componentes automáticos se representan en el servidor durante la representación estática o interactiva del lado servidor (SSR). Los servicios HttpClient no se registran de forma predeterminada en el proyecto principal de un Blazor Web App. Si la aplicación se ejecuta solo con los HttpClient servicios registrados en el .Client
proyecto, como se describe en la sección Agregar el HttpClient
servicio , la ejecución de la aplicación produce un error en tiempo de ejecución:
InvalidOperationException: No se puede proporcionar un valor para la propiedad "Http" en el tipo "... {COMPONENT}'. No hay ningún servicio registrado de tipo "System.Net.Http.HttpClient".
Use cualquiera de los métodos siguientes:
Agregue los servicios HttpClient al proyecto principal para que HttpClient esté disponible durante el SSR. Usa el siguiente registro de servicio en el archivo
Program
del servidor principal:builder.Services.AddHttpClient();
El marco compartido proporciona servicios HttpClient, por lo que no se requiere una referencia de paquete en el archivo de proyecto de la aplicación.
Ejemplo: API web de lista de tareas en la
BlazorWebAppCallWebApi
aplicación de muestraSi la representación previa no es necesaria para un componente de WebAssembly que llama a la API web, deshabilite la representación previa siguiendo las instrucciones de ASP.NET modos de representación de CoreBlazor. Si adoptas este enfoque, no es necesario agregar servicios HttpClient al proyecto principal de la Blazor Web App porque el componente no se representará previamente en el servidor.
Para obtener más información, consulte Los servicios del lado cliente no se resuelven durante la representación previa.
Datos representados previamente
Al representar previamente, los componentes se representan dos veces: primero estáticamente y, después, de forma interactiva. El estado no fluye automáticamente desde el componente creado previamente hasta el interactivo. Si un componente realiza operaciones de inicialización asíncronas y representa diferentes contenidos para diferentes estados durante la inicialización, como un indicador de progreso "Cargando...", puedes ver un parpadeo cuando el componente se representa dos veces.
Para solucionarlo, puede abordar el estado prerenderizado al usar la API de Estado de Componente Persistente, lo cual se demuestra con las aplicaciones de ejemplo data-enhanced-nav=false
). Para obtener más información, consulta los siguientes recursos:
Streaming de solicitudes del lado cliente
En el caso de los exploradores basados en Chromium (por ejemplo, Google Chrome y Microsoft Edge) mediante el protocolo HTTP/2 y HTTPS, el lado Blazor cliente usa Streams API para permitir el streaming de solicitudes.
Para habilitar el streaming de solicitudes, establezca SetBrowserRequestStreamingEnabled a true
en el HttpRequestMessage.
En el ejemplo de carga de archivos siguiente:
-
content
es el HttpContentdel archivo . -
/Filesave
es el punto de conexión de la API web. -
Http
es el HttpClient.
using var request = new HttpRequestMessage(HttpMethod.Post, "/Filesave");
request.SetBrowserRequestStreamingEnabled(true);
request.Content = content;
using var response = await Http.SendAsync(request);
Solicitudes de streaming:
- Requiere el protocolo HTTPS y no funciona en HTTP/1.x.
- Incluya un cuerpo pero no un encabezado
Content-Length
. CORS con una solicitud preparatoria es necesaria para las solicitudes de streaming entre orígenes.
Para obtener más información sobre las cargas de archivos con InputFile component, consulte ASP.NET Core Blazor cargas de archivos y el ejemplo en Carga de archivos en un servidor con representación del lado cliente (CSR).
Añadir el servicio HttpClient
Las instrucciones de esta sección se aplican a los escenarios del lado cliente.
Los componentes del lado del cliente llaman a las API web utilizando un servicio preconfigurado HttpClient, que se centra en realizar peticiones de vuelta al servidor de origen. Se pueden crear configuraciones del servicio HttpClient adicionales para otras API web en el código de desarrollo. Las solicitudes se crean mediante Blazorasistentes JSON o con HttpRequestMessage. Las solicitudes pueden incluir la configuración de la opción Fetch API .
Los ejemplos de configuración de esta sección solo son útiles cuando se llama a una sola API web para una sola instancia HttpClient de la aplicación. Cuando la aplicación debe llamar a varias API web, cada una con su propia dirección base y configuración, puede adoptar los siguientes enfoques, que se tratan más adelante en este artículo:
-
Nombrado
HttpClient
conIHttpClientFactory
: cada API web recibe un nombre único. Cuando el código de la aplicación o un componente Razor llama a una API web, usa una instancia denominada HttpClient para realizar la llamada. -
HttpClient
Con tipo: cada API web está tipificada. Cuando el código de la aplicación o un componente Razor llama a una API web, usa una instancia HttpClient con tipo para realizar la llamada.
En el archivo Program
, añada un servicio HttpClient si no está ya presente desde una plantilla de proyecto Blazor utilizada para crear la aplicación:
builder.Services.AddScoped(sp =>
new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
En el ejemplo anterior se establece la dirección base con builder.HostEnvironment.BaseAddress
(IWebAssemblyHostEnvironment.BaseAddress), que obtiene la dirección base de la aplicación y se deriva normalmente del valor <base>
de la etiqueta href
en la página host.
Los casos de uso más comunes para usar la dirección base del cliente son:
- El proyecto de cliente (
.Client
) de una Blazor Web App (.NET 8 o posterior) realiza llamadas a API web desde componentes o código de WebAssembly que se ejecuta en el cliente de WebAssembly a las API de la aplicación de servidor. - El proyecto de cliente (Client) de una aplicación hospedada Blazor WebAssembly realiza llamadas API web al proyecto de servidor (Server). Tenga en cuenta que la plantilla de proyecto hospedada Blazor WebAssembly ya no está disponible en .NET 8 o posterior. Sin embargo, las aplicaciones hospedadas Blazor WebAssembly siguen siendo compatibles con .NET 8.
Si llamas a una API web externa (que no se encuentra en el mismo espacio de direcciones URL que la aplicación cliente), establece el URI en la dirección base de la API web. En el siguiente ejemplo se establece la dirección base de la API web en https://localhost:5001
, donde se está ejecutando una aplicación de API web independiente y lista para responder a las solicitudes de la aplicación cliente:
builder.Services.AddScoped(sp =>
new HttpClient { BaseAddress = new Uri("https://localhost:5001") });
Asistentes de JSON
HttpClient está disponible como un servicio preconfigurado para realizar solicitudes de vuelta al servidor de origen.
HttpClient y los asistentes de JSON (System.Net.Http.Json.HttpClientJsonExtensions) también se usan para llamar a puntos de conexión de API web de terceros. HttpClientse implementa mediante la API Fetch del explorador y está sujeta a sus limitaciones, incluida la aplicación de la directiva de mismo origen, que se describe más adelante en este artículo en la sección Uso compartido de recursos entre orígenes (CORS).
La dirección base del cliente se establece en la dirección del servidor de origen. Inserta una instancia de HttpClient en un componente con la directiva @inject
:
@using System.Net.Http
@inject HttpClient Http
Usa el espacio de nombres System.Net.Http.Json para acceder a HttpClientJsonExtensions, incluidos GetFromJsonAsync, PutAsJsonAsync y PostAsJsonAsync:
@using System.Net.Http.Json
En las secciones siguientes se tratan las funciones auxiliares JSON.
System.Net.Http incluye métodos adicionales para enviar solicitudes HTTP y recibir respuestas HTTP, por ejemplo, para enviar una solicitud DELETE. Para obtener más información, consulte la sección DELETE y métodos de extensión adicionales .
GET de JSON (GetFromJsonAsync
)
GetFromJsonAsync envía una solicitud HTTP GET y analiza el cuerpo de la respuesta JSON para crear un objeto.
En el código de componente siguiente, el componente muestra el elemento todoItems
. Se llama a GetFromJsonAsync cuando el componente termina de inicializarse (OnInitializedAsync
).
todoItems = await Http.GetFromJsonAsync<TodoItem[]>("todoitems");
POST como JSON (PostAsJsonAsync
)
PostAsJsonAsync envía una solicitud POST al URI especificado que contiene el valor serializado como JSON en el cuerpo de la solicitud.
En el siguiente código de componente, newItemName
es proporcionado por un elemento enlazado del componente. El método AddItem
se desencadena al seleccionar un elemento <button>
.
await Http.PostAsJsonAsync("todoitems", addItem);
PostAsJsonAsync devuelve un valor de HttpResponseMessage. Para deserializar el contenido JSON del mensaje de respuesta, usa el método de extensión ReadFromJsonAsync. En el ejemplo siguiente se leen los datos meteorológicos JSON como una matriz:
var content = await response.Content.ReadFromJsonAsync<WeatherForecast[]>() ??
Array.Empty<WeatherForecast>();
POST como JSON (PutAsJsonAsync
)
PutAsJsonAsync envía una solicitud HTTP PUT con el contenido con codificación JSON.
En el código de componente siguiente, los elementos enlazados del componente proporcionan valores editItem
para Name
e IsCompleted
. El valor Id
del elemento se establece cuando el elemento está seleccionado en otra parte de la interfaz de usuario (no se muestra) y se llama a EditItem
. El método SaveItem
se desencadena al seleccionar el elemento <button>
. En el ejemplo siguiente no se muestra la carga de todoItems
por motivos de brevedad. Consulte la sección GET de JSON (GetFromJsonAsync
) para obtener un ejemplo de carga de elementos.
await Http.PutAsJsonAsync($"todoitems/{editItem.Id}", editItem);
PutAsJsonAsync devuelve un valor de HttpResponseMessage. Para deserializar el contenido JSON del mensaje de respuesta, usa el método de extensión ReadFromJsonAsync. En el ejemplo siguiente se leen los datos meteorológicos JSON como una matriz:
var content = await response.Content.ReadFromJsonAsync<WeatherForecast[]>() ??
Array.Empty<WeatherForecast>();
PATCH como JSON (PatchAsJsonAsync
)
PatchAsJsonAsync envía una solicitud HTTP PATCH con el contenido con codificación JSON.
Nota
Para obtener más información, consulte JsonPatch en ASP.NET CORE web API.
En el siguiente ejemplo, PatchAsJsonAsync recibe un documento JSON PATCH como una cadena de texto sin formato con comillas escapadas:
await Http.PatchAsJsonAsync(
$"todoitems/{id}",
"[{\"operationType\":2,\"path\":\"/IsComplete\",\"op\":\"replace\",\"value\":true}]");
A partir de C# 11 (.NET 7), puedes componer una cadena JSON como un literal de cadena sin procesar. Especifique la sintaxis JSON con el StringSyntaxAttribute.Json campo al [StringSyntax]
atributo para las herramientas de análisis de código:
@using System.Diagnostics.CodeAnalysis
...
@code {
[StringSyntax(StringSyntaxAttribute.Json)]
private const string patchOperation =
"""[{"operationType":2,"path":"/IsComplete","op":"replace","value":true}]""";
...
await Http.PatchAsJsonAsync($"todoitems/{id}", patchOperation);
}
PatchAsJsonAsync devuelve un valor de HttpResponseMessage. Para deserializar el contenido JSON del mensaje de respuesta, usa el método de extensión ReadFromJsonAsync. En el ejemplo siguiente se leen los datos del elemento de tareas pendientes JSON como una matriz. Se crea una matriz vacía si el método no devuelve ningún dato de elemento, por lo que content
no es nulo después de que se ejecuta la instrucción:
using var response = await Http.PatchAsJsonAsync(...);
var content = await response.Content.ReadFromJsonAsync<TodoItem[]>() ??
Array.Empty<TodoItem>();
Dispuesto con sangría, espaciado y comillas sin mayúsculas, el documento PATCH sin codificar aparece como el siguiente JSON:
[
{
"operationType": 2,
"path": "/IsComplete",
"op": "replace",
"value": true
}
]
Para simplificar la creación de documentos PATCH en la aplicación que emite solicitudes PATCH, una aplicación puede usar la compatibilidad con .NET JSON PATCH, como se muestra en las instrucciones siguientes.
Instala el paquete NuGet Microsoft.AspNetCore.JsonPatch.SystemTextJson
y usa las características de API del paquete para crear un JsonPatchDocument
para una solicitud PATCH.
Nota
Para obtener instrucciones sobre cómo agregar paquetes a aplicaciones .NET, consulte los artículos en Instalación y administración de paquetes en el flujo de trabajo de consumo de paquetes (documentación de NuGet). Confirme las versiones correctas del paquete en NuGet.org.
Agregue directivas @using
para los espacios de nombres System.Text.Json, System.Text.Json.Serialization, y Microsoft.AspNetCore.JsonPatch.SystemTextJson
en la parte superior del componente Razor.
@using System.Text.Json
@using System.Text.Json.Serialization
@using Microsoft.AspNetCore.JsonPatch.SystemTextJson
Cree el JsonPatchDocument
para un objeto TodoItem
establecido en IsComplete
true
mediante el método JsonPatchDocument.Replace
:
var patchDocument = new JsonPatchDocument<TodoItem>()
.Replace(p => p.IsComplete, true);
Instala el paquete NuGet Microsoft.AspNetCore.JsonPatch
y usa las características de API del paquete para crear un JsonPatchDocument para una solicitud PATCH.
Nota
Para obtener instrucciones sobre cómo agregar paquetes a aplicaciones .NET, consulte los artículos en Instalación y administración de paquetes en el flujo de trabajo de consumo de paquetes (documentación de NuGet). Confirme las versiones correctas del paquete en NuGet.org.
Agrega directivas @using
para los espacios de nombres System.Text.Json, System.Text.Json.Serialization y Microsoft.AspNetCore.JsonPatch en la parte superior del componente Razor :
@using System.Text.Json
@using System.Text.Json.Serialization
@using Microsoft.AspNetCore.JsonPatch
Cree el JsonPatchDocument para un objeto TodoItem
establecido en IsComplete
true
mediante el método Replace:
var patchDocument = new JsonPatchDocument<TodoItem>()
.Replace(p => p.IsComplete, true);
Pase las operaciones del documento (patchDocument.Operations
) a la llamada PatchAsJsonAsync:
private async Task UpdateItem(long id)
{
await Http.PatchAsJsonAsync(
$"todoitems/{id}",
patchDocument.Operations,
new JsonSerializerOptions()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault
});
}
JsonSerializerOptions.DefaultIgnoreCondition se establece como JsonIgnoreCondition.WhenWritingDefault para omitir una propiedad solo si es igual al valor predeterminado de su tipo.
Añada JsonSerializerOptions.WriteIndented ajustado a true
si desea presentar la carga útil JSON en un formato agradable para su visualización. Escribir JSON sangrado no tiene ninguna relación con el procesamiento de solicitudes PATCH y no se suele realizar en aplicaciones de producción para solicitudes de API web.
Siga las instrucciones del artículo JsonPatch en ASP.NET API web core para agregar una acción del controlador PATCH a la API web. Como alternativa, el procesamiento de solicitudes PATCH se puede implementar como una API mínima con los pasos siguientes.
Agrega una referencia de paquete para el paquete NuGet Microsoft.AspNetCore.JsonPatch.SystemTextJson
a la aplicación de API web.
En el Program
archivo agregue una @using
directiva para el Microsoft.AspNetCore.JsonPatch.SystemTextJson
espacio de nombres.
using Microsoft.AspNetCore.JsonPatch.SystemTextJson;
Agrega una referencia de paquete para el paquete NuGet Microsoft.AspNetCore.Mvc.NewtonsoftJson
a la aplicación de API web.
Nota
No es necesario agregar una referencia de paquete para el paquete Microsoft.AspNetCore.JsonPatch
a la aplicación porque la referencia al paquete Microsoft.AspNetCore.Mvc.NewtonsoftJson
agrega automáticamente una referencia de paquete para Microsoft.AspNetCore.JsonPatch
.
En el archivo Program
, agrega una directiva @using
para el espacio de nombres Microsoft.AspNetCore.JsonPatch:
using Microsoft.AspNetCore.JsonPatch;
Proporciona el punto de conexión a la canalización de procesamiento de solicitudes de la API web:
app.MapPatch("/todoitems/{id}", async (long id, TodoContext db) =>
{
if (await db.TodoItems.FindAsync(id) is TodoItem todo)
{
var patchDocument =
new JsonPatchDocument<TodoItem>().Replace(p => p.IsComplete, true);
patchDocument.ApplyTo(todo);
await db.SaveChangesAsync();
return TypedResults.Ok(todo);
}
return TypedResults.NoContent();
});
Advertencia
Al igual que con los otros ejemplos del JsonPatch en el artículo de API web de ASP.NET Core, la API PATCH anterior no protege la API web frente a ataques de sobrecarga de publicación. Para obtener más información, consulte Tutorial: Creación de una API web basada en controlador con ASP.NET Core.
Para obtener una experiencia PATCH totalmente funcional, consulte la BlazorWebAppCallWebApi
aplicación de ejemplo.
DELETE (DeleteAsync
) y métodos de extensión adicionales
System.Net.Http incluye métodos de extensión adicionales para enviar solicitudes HTTP y recibir respuestas HTTP. HttpClient.DeleteAsync se usa para enviar una solicitud HTTP DELETE a una API web.
En el código de componente siguiente, el elemento <button>
llama al método DeleteItem
. El elemento <input>
enlazado proporciona el valor id
del elemento que se va a eliminar.
await Http.DeleteAsync($"todoitems/{id}");
Denominado HttpClient
con IHttpClientFactory
Se admiten los servicios IHttpClientFactory y la configuración de un HttpClient con nombre.
Nota
Una alternativa al uso de un HttpClient con nombre a partir de un IHttpClientFactory es utilizar un HttpClient con tipo. Para obtener más información, consulte la sección Con tipo HttpClient
.
Agrega el paquete NuGet Microsoft.Extensions.Http
a la aplicación.
Nota
Para obtener instrucciones sobre cómo agregar paquetes a aplicaciones .NET, consulte los artículos en Instalación y administración de paquetes en el flujo de trabajo de consumo de paquetes (documentación de NuGet). Confirme las versiones correctas del paquete en NuGet.org.
En el archivo Program
de un proyecto de cliente:
builder.Services.AddHttpClient("WebAPI", client =>
client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress));
Si el cliente nombrado va a ser utilizado por componentes prerenderizados del lado del cliente de un Blazor Web App, el registro de servicio precedente debe aparecer tanto en el proyecto del servidor como en el proyecto .Client
. En el servidor, builder.HostEnvironment.BaseAddress
se reemplaza por la dirección base de la API web, que se describe más adelante.
En el ejemplo anterior del lado cliente se establece la dirección base con builder.HostEnvironment.BaseAddress
(IWebAssemblyHostEnvironment.BaseAddress), que obtiene la dirección base de la aplicación del lado cliente y se deriva normalmente del valor <base>
de la etiqueta href
en la página host.
Los casos de uso más comunes para usar la dirección base del cliente son:
- El proyecto de cliente (
.Client
) de una aplicación web Blazor Web App que realiza llamadas a la API web desde componentes WebAssembly/Auto o código que se ejecuta en el cliente en WebAssembly a las API de la aplicación del servidor en la misma dirección de host. - El proyecto cliente (Client) de una aplicación Blazor WebAssembly hospedada que realiza llamadas API web al proyecto de servidor (Server).
El caso de uso más común para usar la propia dirección base del cliente está en el proyecto de cliente (Client) de una aplicación hospedada Blazor WebAssembly que realiza llamadas API web al proyecto de servidor (Server).
Si llamas a una API web externa (no en el mismo espacio de direcciones URL que la aplicación cliente) o configuras los servicios en una aplicación del lado servidor (por ejemplo, para tratar la representación previa de componentes del lado cliente en el servidor), establece el URI en la dirección base de la API web. En el siguiente ejemplo se establece la dirección base de la API web en https://localhost:5001
, donde se está ejecutando una aplicación de API web independiente y lista para responder a las solicitudes de la aplicación cliente:
builder.Services.AddHttpClient("WebAPI", client =>
client.BaseAddress = new Uri("https://localhost:5001"));
En el siguiente código de componente:
- Una instancia de IHttpClientFactory crea un HttpClient con nombre.
- El elemento denominado HttpClient se usa para realizar una solicitud GET para obtener datos JSON de previsión meteorológica desde la API web en
/forecast
.
@inject IHttpClientFactory ClientFactory
...
@code {
private Forecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
var client = ClientFactory.CreateClient("WebAPI");
forecasts = await client.GetFromJsonAsync<Forecast[]>("forecast") ?? [];
}
}
La BlazorWebAppCallWebApi
aplicación de ejemplo muestra cómo llamar a una API web con un nombre HttpClient en su CallTodoWebApiCsrNamedClient
componente. Para obtener una demostración de trabajo adicional en una aplicación cliente basada en llamar a Microsoft Graph con un denominado HttpClient, consulte Uso de Graph API con ASP.NET Core Blazor WebAssembly.
Para obtener una demostración de trabajo en una aplicación cliente basada en llamar a Microsoft Graph con un denominado HttpClient, consulte Uso de Graph API con ASP.NET Core Blazor WebAssembly.
Con tipo HttpClient
Typed HttpClient utiliza una o varias instancias de HttpClient de la aplicación, ya sean predeterminadas o con nombre, para devolver datos de uno o varios puntos de conexión de la API web.
Nota
Una alternativa al uso de un objeto HttpClient con tipo es usar un HttpClient con nombre desde IHttpClientFactory. Para obtener más información, consulte la sección DenominadaHttpClient
IHttpClientFactory
.
Agrega el paquete NuGet Microsoft.Extensions.Http
a la aplicación.
Nota
Para obtener instrucciones sobre cómo agregar paquetes a aplicaciones .NET, consulte los artículos en Instalación y administración de paquetes en el flujo de trabajo de consumo de paquetes (documentación de NuGet). Confirme las versiones correctas del paquete en NuGet.org.
El siguiente ejemplo emite una solicitud GET para datos de pronóstico del tiempo JSON desde la API web en /forecast
.
ForecastHttpClient.cs
:
using System.Net.Http.Json;
namespace BlazorSample.Client;
public class ForecastHttpClient(HttpClient http)
{
public async Task<Forecast[]> GetForecastAsync() =>
await http.GetFromJsonAsync<Forecast[]>("forecast") ?? [];
}
En el archivo Program
de un proyecto de cliente:
builder.Services.AddHttpClient<ForecastHttpClient>(client =>
client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress));
Si el cliente nombrado va a ser utilizado por componentes prerenderizados del lado del cliente de un Blazor Web App, el registro de servicio precedente debe aparecer tanto en el proyecto del servidor como en el proyecto .Client
. En el servidor, builder.HostEnvironment.BaseAddress
se reemplaza por la dirección base de la API web, que se describe más adelante.
En el ejemplo anterior se establece la dirección base con builder.HostEnvironment.BaseAddress
(IWebAssemblyHostEnvironment.BaseAddress), que obtiene la dirección base de la aplicación del lado cliente y se deriva normalmente del valor <base>
de la etiqueta href
en la página host.
Los casos de uso más comunes para usar la dirección base del cliente son:
- El proyecto de cliente (
.Client
) de una aplicación web Blazor Web App que realiza llamadas a la API web desde componentes WebAssembly/Auto o código que se ejecuta en el cliente en WebAssembly a las API de la aplicación del servidor en la misma dirección de host. - El proyecto cliente (Client) de una aplicación Blazor WebAssembly hospedada que realiza llamadas API web al proyecto de servidor (Server).
El caso de uso más común para usar la propia dirección base del cliente está en el proyecto de cliente (Client) de una aplicación hospedada Blazor WebAssembly que realiza llamadas API web al proyecto de servidor (Server).
Si llamas a una API web externa (no en el mismo espacio de direcciones URL que la aplicación cliente) o configuras los servicios en una aplicación del lado servidor (por ejemplo, para tratar la representación previa de componentes del lado cliente en el servidor), establece el URI en la dirección base de la API web. En el siguiente ejemplo se establece la dirección base de la API web en https://localhost:5001
, donde se está ejecutando una aplicación de API web independiente y lista para responder a las solicitudes de la aplicación cliente:
builder.Services.AddHttpClient<ForecastHttpClient>(client =>
client.BaseAddress = new Uri("https://localhost:5001"));
Los componentes insertan la instancia de HttpClient con tipo para llamar a la API web.
En el siguiente código de componente:
- Se inserta una instancia de la clase
ForecastHttpClient
anterior, que crea un objeto con tipo HttpClient. - El tipo HttpClient se usa para emitir una solicitud GET para obtener datos JSON de previsión meteorológica desde la API web.
@inject ForecastHttpClient Http
...
@code {
private Forecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
forecasts = await Http.GetForecastAsync();
}
}
La BlazorWebAppCallWebApi
aplicación de ejemplo muestra cómo llamar a una API web con un HttpClient tipado en su componente CallTodoWebApiCsrTypedClient
. Tenga en cuenta que el componente adopta la representación del lado del cliente (CSR) (InteractiveWebAssembly
modo de representación) con prerenderización, de modo que el registro del servicio cliente tipado aparece en el archivo Program
del proyecto del servidor y el proyecto .Client
.
Credenciales de solicitud basadas en Cookie
La guía de esta sección se aplica a los escenarios del lado cliente que se basan en una autenticación cookie.
Para la autenticación basada en cookie, que se considera más segura que la autenticación de token de portador, las credenciales cookie se pueden enviar con cada solicitud de API web llamando a AddHttpMessageHandler con un DelegatingHandler en un HttpClient preconfigurado. El controlador configura SetBrowserRequestCredentials con BrowserRequestCredentials.Include, que aconseja al explorador que envíe credenciales con cada solicitud, como cookies o encabezados de autenticación HTTP, incluso para solicitudes entre orígenes.
CookieHandler.cs
:
public class CookieHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);
request.Headers.Add("X-Requested-With", [ "XMLHttpRequest" ]);
return base.SendAsync(request, cancellationToken);
}
}
Nota
Para obtener instrucciones sobre cómo acceder a un AuthenticationStateProvider
desde un DelegatingHandler
, consulte ASP.NET Core del lado del servidor y escenarios de seguridad adicionalesBlazor Web App.
CookieHandler
se registra en el archivo Program
:
builder.Services.AddTransient<CookieHandler>();
El controlador de mensajes se agrega a cualquier HttpClient preconfigurado que requiera autenticación cookie:
builder.Services.AddHttpClient(...)
.AddHttpMessageHandler<CookieHandler>();
Para obtener una demostración, consulte Protección de ASP.NET Core Blazor WebAssembly con ASP.NET Core Identity.
Al redactar un HttpRequestMessage, establece las credenciales de solicitud del explorador y el encabezado directamente:
using var request = new HttpRequestMessage() { ... };
request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);
request.Headers.Add("X-Requested-With", [ "XMLHttpRequest" ]);
HttpClient
y HttpRequestMessage
con las opciones de solicitud de Fetch API
La guía de esta sección se aplica a los escenarios del lado cliente que dependen de la autenticación de tokens de portador.
HttpClient
(documentación de API) y HttpRequestMessage se puede usar para personalizar las solicitudes. Por ejemplo, se puede especificar el método HTTP y los encabezados de solicitud. El siguiente componente realiza una solicitud POST
a un punto de conexión de API web y muestra el cuerpo de la respuesta.
TodoRequest.razor
:
@page "/todo-request"
@using System.Net.Http.Headers
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject HttpClient Http
@inject IAccessTokenProvider TokenProvider
<h1>ToDo Request</h1>
<h1>ToDo Request Example</h1>
<button @onclick="PostRequest">Submit POST request</button>
<p>Response body returned by the server:</p>
<p>@responseBody</p>
@code {
private string? responseBody;
private async Task PostRequest()
{
using var request = new HttpRequestMessage()
{
Method = new HttpMethod("POST"),
RequestUri = new Uri("https://localhost:10000/todoitems"),
Content =
JsonContent.Create(new TodoItem
{
Name = "My New Todo Item",
IsComplete = false
})
};
var tokenResult = await TokenProvider.RequestAccessToken();
if (tokenResult.TryGetToken(out var token))
{
request.Headers.Authorization =
new AuthenticationHeaderValue("Bearer", token.Value);
request.Content.Headers.TryAddWithoutValidation(
"x-custom-header", "value");
using var response = await Http.SendAsync(request);
var responseStatusCode = response.StatusCode;
responseBody = await response.Content.ReadAsStringAsync();
}
}
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
}
BlazorLa implementación en el lado del cliente de HttpClient utiliza Fetch API y configura las opciones de Fetch API específicas de la solicitud mediante HttpRequestMessage métodos de extensión y WebAssemblyHttpRequestMessageExtensions. Establece más opciones usando el método de extensión SetBrowserRequestOption genérico. Blazor y la API Fetch subyacente no agregan ni modifican directamente los encabezados de solicitud. Para obtener más información sobre cómo los agentes de usuario, como los exploradores, interactúan con los encabezados, consulta los conjuntos de documentación del agente de usuario externo y otros recursos web.
El streaming de respuesta está habilitado de forma predeterminada.
La llamada a HttpContent.ReadAsStreamAsync para un HttpResponseMessage.Content (response.Content.ReadAsStreamAsync()
) devuelve un BrowserHttpReadStream
(origen de referencia), no un MemoryStream.
BrowserHttpReadStream
no admite operaciones sincrónicas, como Stream.Read(Span<Byte>)
. Si su código utiliza operaciones sincrónicas, puede optar por no participar en la transmisión de respuesta o copiar el Stream en el MemoryStream usted mismo.
Nota
Los vínculos de la documentación al origen de referencia de .NET cargan normalmente la rama predeterminada del repositorio, que representa el desarrollo actual para la próxima versión de .NET. Para seleccionar una etiqueta para una versión específica, use la lista desplegable Cambiar ramas o etiquetas . Para obtener más información, vea Cómo seleccionar una etiqueta de versión de ASP.NET código fuente de Core (dotnet/AspNetCore.Docs #26205).
Para no participar en el streaming de respuesta globalmente, use cualquiera de los enfoques siguientes:
Agregue la
<WasmEnableStreamingResponse>
propiedad al archivo de proyecto con un valor defalse
:<WasmEnableStreamingResponse>false</WasmEnableStreamingResponse>
Establezca la variable de
DOTNET_WASM_ENABLE_STREAMING_RESPONSE
entorno enfalse
o0
.
Para excluirse del streaming de respuesta para una solicitud individual, establezca SetBrowserResponseStreamingEnabled en false
en HttpRequestMessage (request
en el ejemplo siguiente):
request.SetBrowserResponseStreamingEnabled(false);
Normalmente, la respuesta HTTP se almacena en búfer para habilitar la compatibilidad con las lecturas sincrónicas en el contenido de la respuesta. Para habilitar la compatibilidad con el streaming de respuesta, establezca SetBrowserResponseStreamingEnabled en true
en HttpRequestMessage:
request.SetBrowserResponseStreamingEnabled(true);
De forma predeterminada, se establece HttpCompletionOption.ResponseContentRead
, lo que da como resultado que HttpClient complete después de leer toda la respuesta, incluido el contenido. Para poder usar la SetBrowserResponseStreamingEnabled opción en archivos grandes, establezca HttpCompletionOption.ResponseHeadersRead
para evitar almacenar en caché el contenido del archivo en memoria:
- using var response = await Http.SendAsync(request);
+ using var response = await Http.SendAsync(request,
+ HttpCompletionOption.ResponseHeadersRead);
Para incluir credenciales en una solicitud entre orígenes, usa el método de extensión SetBrowserRequestCredentials:
request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);
Para obtener más información sobre las opciones de Fetch API, consulte documentos web de MDN: WindowOrWorkerGlobalScope.fetch(): Parameters.
Manejo de errores
Controla los errores de respuesta de la API web en el código de desarrollo cuando se produzcan. Por ejemplo, GetFromJsonAsync espera una respuesta JSON de la API web con un Content-Type
de application/json
. Si la respuesta no está en formato JSON, la validación del contenido producirá una excepción NotSupportedException.
En el ejemplo siguiente, el punto de conexión del URI para la solicitud de datos de previsión meteorológica está mal escrito. El URI debe ser WeatherForecast
, pero aparece en la llamada como WeatherForcast
, y le falta la letra e
en Forecast
.
La llamada a GetFromJsonAsync espera que se devuelva JSON, pero la API web devuelve HTML para una excepción no controlada con un Content-Type
de text/html
. La excepción no controlada se produce porque no se encuentra la ruta de acceso a /WeatherForcast
y el middleware no puede proporcionar una página o vista para la solicitud.
En OnInitializedAsync en el cliente, se produce una excepción NotSupportedException cuando el contenido de la respuesta se valida como distinto de JSON. La excepción se captura en el bloque catch
, donde la lógica personalizada podría registrar el error o mostrar al usuario un mensaje de error descriptivo:
ReturnHTMLOnException.razor
:
@page "/return-html-on-exception"
@using {PROJECT NAME}.Shared
@inject HttpClient Http
<h1>Fetch data but receive HTML on unhandled exception</h1>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<h2>Temperatures by Date</h2>
<ul>
@foreach (var forecast in forecasts)
{
<li>
@forecast.Date.ToShortDateString():
@forecast.TemperatureC ℃
@forecast.TemperatureF ℉
</li>
}
</ul>
}
<p>
@exceptionMessage
</p>
@code {
private WeatherForecast[]? forecasts;
private string? exceptionMessage;
protected override async Task OnInitializedAsync()
{
try
{
// The URI endpoint "WeatherForecast" is misspelled on purpose on the
// next line. See the preceding text for more information.
forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForcast");
}
catch (NotSupportedException exception)
{
exceptionMessage = exception.Message;
}
}
}
Nota
El ejemplo anterior sirve de demostración. Se puede configurar una API web para que devuelva JSON incluso cuando no existe un punto de conexión o cuando se produce una excepción no controlada en el servidor.
Para obtener más información, consulte Control de errores en aplicaciones de ASP.NET CoreBlazor.
Uso compartido de recursos entre orígenes (CORS)
La seguridad del explorador suele restringir que una página web realice solicitudes a un origen diferente al que actuó en la página web. Esta restricción se denomina directiva de mismo origen. La directiva de mismo origen restringe, pero no impide, que un sitio malintencionado lea información confidencial de otro sitio. Para realizar solicitudes desde el explorador a un punto de conexión con un origen diferente, el punto de conexión debe habilitar el uso compartido de recursos entre orígenes (CORS).
Para obtener más información sobre CORS del lado servidor, vea Habilitar solicitudes entre orígenes (CORS) en ASP.NET Core. Los ejemplos del artículo no pertenecen directamente a los escenarios de los componentes Razor, pero el artículo es útil para aprender conceptos generales de CORS.
Para obtener información sobre las solicitudes CORS del lado cliente, consulte ASP.NET Escenarios de seguridad adicionales de CoreBlazor WebAssembly.
Soporte para la prevención de falsificaciones
Para agregar compatibilidad antiforgería a una solicitud HTTP, inserta AntiforgeryStateProvider
y agrega un RequestToken
a la colección de encabezados como un RequestVerificationToken
:
@inject AntiforgeryStateProvider Antiforgery
private async Task OnSubmit()
{
var antiforgery = Antiforgery.GetAntiforgeryToken();
using var request = new HttpRequestMessage(HttpMethod.Post, "action");
request.Headers.Add("RequestVerificationToken", antiforgery.RequestToken);
using var response = await client.SendAsync(request);
...
}
Para obtener más información, consulte ASP.NET Core Blazor autenticación y autorización.
Ejemplos de componentes del marco Blazor para probar el acceso a la API web
Hay varias herramientas de red disponibles públicamente para probar aplicaciones back-end de API web directamente, como Firefox Browser Developer. El origen de referencia del marco Blazor incluye recursos de prueba HttpClient que son útiles para las pruebas:
HttpClientTest
recursos en el repositorio de dotnet/aspnetcore
GitHub
Nota
Los vínculos de la documentación al origen de referencia de .NET cargan normalmente la rama predeterminada del repositorio, que representa el desarrollo actual para la próxima versión de .NET. Para seleccionar una etiqueta para una versión específica, use la lista desplegable Cambiar ramas o etiquetas . Para obtener más información, vea Cómo seleccionar una etiqueta de versión de ASP.NET código fuente de Core (dotnet/AspNetCore.Docs #26205).
Recursos adicionales
General
- Uso compartido de recursos entre orígenes (CORS) en W3C
- Habilitación de solicitudes entre orígenes (CORS) en ASP.NET Core: aunque el contenido se aplica a aplicaciones de ASP.NET Core y no a los componentes, el artículo trata los conceptos generales de CORS.
- Protección de datos en Blazor Web Apps con representación automática interactiva
- Uso compartido de recursos entre orígenes (CORS) en W3C
- Habilitación de solicitudes entre orígenes (CORS) en ASP.NET Core: aunque el contenido se aplica a aplicaciones de ASP.NET Core y no a los componentes, el artículo trata los conceptos generales de CORS.
Mitigación de ataques por publicación excesiva
Las API web pueden ser vulnerables a un ataque de sobrepostificación , también conocido como ataque de asignación masiva . Un ataque por publicación excesiva se produce cuando un usuario malintencionado emite una instrucción POST de formulario HTML en el servidor que procesa los datos de las propiedades que no forman parte del formulario representado y que el desarrollador no desea permitir que los usuarios modifiquen. El término "overposting" significa literalmente que el usuario malintencionado ha realizado más solicitudes POST de las necesarias con el formulario.
Para obtener instrucciones sobre la mitigación de ataques de sobrepostificación, consulte Tutorial: Creación de una API web basada en controlador con ASP.NET Core.
Lado servidor
- Blazor Web App: incluye cobertura sobre el uso de para realizar solicitudes de API web seguras.
- Realización de solicitudes HTTP con IHttpClientFactory en ASP.NET Core
- Aplicar HTTPS en ASP.NET Core
- Kestrel Configuración del punto de conexión HTTPS
Lado cliente
- Escenarios de seguridad adicionales de ASP.NET CoreBlazor WebAssembly: incluye cobertura sobre el uso de HttpClient para realizar solicitudes de API web seguras.
- Uso de Graph API con ASP.NET Core Blazor WebAssembly
- Fetch API