Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Observação
Esta não é a versão mais recente deste artigo. Para a versão atual, consulte a versão .NET 9 deste artigo.
Advertência
Esta versão do ASP.NET Core não é mais suportada. Para obter mais informações, consulte a Política de suporte do .NET e do .NET Core. Para a versão atual, consulte a versão .NET 9 deste artigo.
Importante
Estas informações referem-se a um produto de pré-lançamento que pode ser substancialmente modificado antes de ser lançado comercialmente. A Microsoft não oferece garantias, expressas ou implícitas, em relação às informações fornecidas aqui.
Para a versão atual, consulte a versão .NET 9 deste artigo.
Este artigo descreve como chamar uma API da Web a partir de um aplicativo Blazor.
Embalagem
O pacote System.Net.Http.Json
fornece métodos de extensão para System.Net.Http.HttpClient e System.Net.Http.HttpContent que executam serialização e desserialização automáticas usando System.Text.Json
. O pacote System.Net.Http.Json
é fornecido pela estrutura compartilhada do .NET e não requer a adição de uma referência de pacote ao aplicativo.
Usar um manipulador de token para chamadas de API da Web
Blazor Web Apps com autenticação OIDC podem usar uma abordagem de manipulador de token para realizar chamadas de API da Web externas de forma segura. Esta abordagem é utilizada pelos aplicativos de exemplo BlazorWebAppOidc
e BlazorWebAppOidcServer
descritos na seção Aplicativos de exemplo deste artigo.
Para obter mais informações, consulte os seguintes recursos:
- ASP.NET Core do lado do servidor e Blazor Web App cenários de segurança adicionais
- Proteja um ASP.NET Core Blazor Web App com OpenID Connect (OIDC)
Plataforma de identidade da Microsoft para chamadas de API da Web
Blazor Web Apps que usam a plataforma de identidade da Microsoft com pacotes da Web da Microsoft Identity para oMicrosoft Entra ID podem fazer chamadas de API da Web simplificadas com a Microsoft.Identity.Web.DownstreamApi
API fornecida pelo pacote NuGet.
Observação
Para obter orientação sobre como adicionar pacotes a aplicativos .NET, consulte os artigos em Instalar e gerenciar pacotes em Fluxo de trabalho de consumo de pacotes (documentação do NuGet). Confirme as versões corretas do pacote em NuGet.org.
No arquivo de configurações do aplicativo (appsettings.json
), forneça uma URL base e escopos. No exemplo a seguir, o marcador de posição {BASE ADDRESS}
é a URL base da API da Web. Um único escopo é especificado com um URI de identificação de aplicativo ({APP ID URI}
espaço reservado) e nome de escopo ({SCOPE NAME}
espaço reservado):
"DownstreamApi": {
"BaseUrl": "{BASE ADDRESS}",
"Scopes": [ "{APP ID URI}/{SCOPE NAME}" ]
}
Exemplo:
"DownstreamApi": {
"BaseUrl": "https://localhost:7277",
"Scopes": [ "api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get" ]
}
No ficheiro da Program
aplicação, chame:
- EnableTokenAcquisitionToCallDownstreamApi: Permite a aquisição de tokens para chamar APIs da Web.
-
AddDownstreamApi
: Os pacotes da Web da Microsoft Identity fornecem uma API para criar um serviço Web downstream com nome para fazer chamadas de API Web. IDownstreamApi é injetado numa classe server-side, que é usada para chamar CallApiForUserAsync para obter dados meteorológicos de uma API web externa (MinimalApiJwt
projeto). - AddDistributedTokenCaches: Adiciona os caches de tokenes distribuídos do .NET Core à coleção de serviços.
- AddDistributedMemoryCache: Adiciona uma implementação padrão de IDistributedCache que armazena itens de cache na memória.
- Configure as opções de cache de token distribuído (MsalDistributedTokenCacheAdapterOptions):
- No desenvolvimento para fins de depuração, você pode desabilitar o cache L1 definindo DisableL1Cache como
true
. Certifique-se de reverter parafalse
para produção. - Defina o tamanho máximo do cache L1 para
L1CacheOptions.SizeLimit
evitar que o cache exceda a memória do servidor. O valor padrão é 500 MB. - No desenvolvimento para fins de depuração, você pode desabilitar a criptografia de token em repouso definindo Encrypt como
false
, que é o valor padrão. Certifique-se de reverter paratrue
para produção. - Defina a remoção de token do cache com SlidingExpiration. O valor padrão é 1 hora.
- Para obter mais informações, incluindo orientação sobre o retorno de chamada para falhas de cache L2 (OnL2CacheFailure) e gravações assíncronas de cache L2 (EnableAsyncL2Write), consulte MsalDistributedTokenCacheAdapterOptions e Serialização de cache de tokens: caches de tokens distribuídos.
- No desenvolvimento para fins de depuração, você pode desabilitar o cache L1 definindo DisableL1Cache como
Você pode optar por criptografar o cache e deve sempre fazê-lo na produção.
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);
});
Os caches de token distribuído na memória são criados durante a chamada AddDistributedTokenCaches para garantir que haja uma implementação base disponível para o cache de token distribuído.
Aplicativos Web de produção e APIs Web devem usar um cache de token distribuído de produção (por exemplo: Redis, Microsoft SQL Server, Microsoft Azure Cosmos DB).
Observação
Para desenvolvimento local e teste em uma única máquina, você pode usar caches de token na memória em vez de caches de token distribuído:
builder.Services.AddInMemoryTokenCaches();
Mais tarde, durante o período de desenvolvimento e teste, adote um provedor de cache distribuído de tokens em produção.
AddDistributedMemoryCache adiciona uma implementação padrão de IDistributedCache que armazena itens de cache na memória, sendo esta utilizada pela Microsoft Identity Web para o armazenamento em cache de tokens.
AddDistributedMemoryCache requer uma referência de pacote para o Microsoft.Extensions.Caching.Memory
pacote NuGet.
Observação
Para obter orientação sobre como adicionar pacotes a aplicativos .NET, consulte os artigos em Instalar e gerenciar pacotes em Fluxo de trabalho de consumo de pacotes (documentação do NuGet). Confirme as versões corretas do pacote em NuGet.org.
Para configurar um provedor de cache distribuído de produção, consulte Cache distribuído no ASP.NET Core.
Advertência
Substitua sempre os caches de tokens distribuídos em memória por um provedor real de cache de tokens ao implementar a aplicação num ambiente de produção. Se você não adotar um provedor de cache de token distribuído de produção, o aplicativo poderá sofrer um desempenho significativamente degradado.
Para obter mais informações, consulte Serialização de cache de token: caches distribuídos. No entanto, os exemplos de código mostrados não se aplicam aos aplicativos ASP.NET Core, que configuram caches distribuídos via AddDistributedMemoryCache, não AddDistributedTokenCache.
Use um chaveiro compartilhado de Proteção de Dados em produção para que instâncias do aplicativo em servidores em uma web farm possam descriptografar tokens quando MsalDistributedTokenCacheAdapterOptions.Encrypt estiver definido como true
.
Observação
Para desenvolvimento inicial e testes locais em uma única máquina, você pode definir Encrypt para false
e configurar um anel de chaves compartilhado de Proteção de Dados mais tarde.
options.Encrypt = false;
Mais tarde, no período de desenvolvimento e teste, habilite a criptografia de token e adote um chaveiro compartilhado de Proteção de Dados.
O exemplo a seguir mostra como usar o Armazenamento de Blobs do Azure e o Cofre de Chaves do Azure (PersistKeysToAzureBlobStorage
/ProtectKeysWithAzureKeyVault
) para o conjunto de chaves compartilhado. As configurações de serviço são cenários de caso base para fins de demonstração. Antes de implantar aplicativos de produção, familiarize-se com os serviços do Azure e adote práticas recomendadas usando os conjuntos de documentação dedicados dos serviços do Azure, que são vinculados no final desta seção.
Adicione os seguintes pacotes ao projeto de servidor do Blazor Web App:
Observação
Para obter orientação sobre como adicionar pacotes a aplicativos .NET, consulte os artigos em Instalar e gerenciar pacotes em Fluxo de trabalho de consumo de pacotes (documentação do NuGet). Confirme as versões corretas do pacote em NuGet.org.
Observação
Antes de prosseguir com as etapas a seguir, confirme se o aplicativo está registrado no Microsoft Entra.
Configure o Armazenamento de Blobs do Azure para manter as chaves de proteção de dados. Siga as orientações em Provedores de armazenamento de chaves no ASP.NET Core.
Configure o Azure Key Vault para criptografar as chaves de proteção de dados em repouso. Siga as orientações em Configurar ASP.NET Proteção de Dados Principais.
Use o seguinte código no arquivo onde os Program
serviços estão registrados:
TokenCredential? credential;
if (builder.Environment.IsProduction())
{
credential = new ManagedIdentityCredential("{MANAGED IDENTITY CLIENT ID}");
}
else
{
// Local development and testing only
DefaultAzureCredentialOptions options = new()
{
// Specify the tenant ID to use the dev credentials when running the app locally
// in Visual Studio.
VisualStudioTenantId = "{TENANT ID}",
SharedTokenCacheTenantId = "{TENANT ID}"
};
credential = new DefaultAzureCredential(options);
}
builder.Services.AddDataProtection()
.SetApplicationName("{APPLICATION NAME}")
.PersistKeysToAzureBlobStorage(new Uri("{BLOB URI}"), credential)
.ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), credential);
{MANAGED IDENTITY CLIENT ID}
: A ID do Cliente Gerenciado Identity do Azure (GUID).
{TENANT ID}
: ID do inquilino.
{APPLICATION NAME}
: SetApplicationName define o nome exclusivo deste aplicativo dentro do sistema de proteção de dados. O valor deve corresponder entre as implantações do aplicativo.
{BLOB URI}
: URI completo para o arquivo de chave. O URI é gerado pelo Armazenamento do Azure quando você cria o arquivo de chave. Não utilize uma SAS.
{KEY IDENTIFIER}
: Identificador de chave do Azure Key Vault usado para criptografia de chave. Uma política de acesso permite que o aplicativo aceda o cofre de chaves com Get
, Unwrap Key
e permissões Wrap Key
. O identificador de chave é obtido a partir da chave no portal do Entra ou do Azure após a sua criação. Se ativar a rotação automática da chave no cofre de chaves, certifique-se de usar um identificador de chave sem versão na configuração do cofre de chaves do aplicativo, em que nenhum GUID de chave é colocado no final do identificador (exemplo: https://contoso.vault.azure.net/keys/data-protection
).
Observação
Em ambientes que não são de produção, o exemplo anterior usa DefaultAzureCredential para simplificar a autenticação ao desenvolver aplicativos que implantam no Azure combinando credenciais usadas em ambientes de hospedagem do Azure com credenciais usadas no desenvolvimento local. Ao passar para a produção, uma alternativa é uma escolha melhor, como a mostrada ManagedIdentityCredential no exemplo anterior. Para obter mais informações, consulte Autenticar aplicativos .NET hospedados no Azure em recursos do Azure usando uma identidade gerenciada atribuída ao sistema.
Injetar IDownstreamApi e ligar CallApiForUserAsync ao ligar em nome de um usuário:
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!");
}
}
Esta abordagem é utilizada pelos aplicativos de exemplo BlazorWebAppEntra
e BlazorWebAppEntraBff
descritos na seção Aplicativos de exemplo deste artigo.
Para obter mais informações, consulte os seguintes recursos:
- Principais provedores de armazenamento no ASP.NET Core
- Configurar ASP.NET Proteção de Dados Principais
- Usar o SDK do Azure para .NET em aplicativos ASP.NET Core
- Documentação da API Web | Plataforma de identidade da Microsoft
- Uma API da Web que chama APIs da Web: Chamar uma API: Opção 2: Chamar uma API da Web subsequente com a classe auxiliar
- IDownstreamApi
- Proteja um ASP.NET Core Blazor Web App com o Microsoft Entra ID
- Host ASP.NET Core em uma web farm: Proteção de dados
- Documentação do Azure Key Vault
- Documentação do Armazenamento do Azure
- Proporcionar acesso a chaves, certificados e segredos do Key Vault com controlo de acesso baseado em função no Azure
Aplicativos de exemplo
Para obter exemplos de trabalho, consulte os seguintes aplicativos de exemplo no Blazor repositório GitHub de exemplo (dotnet/blazor-samples
) (como fazer o download).
BlazorWebAppCallWebApi
Invoque uma API Web de lista de tarefas externa (não na Blazor Web App) a partir de um Blazor Web App:
-
Backend
: Uma aplicação API web para manter uma lista de tarefas, com base em Minimal APIs. O aplicativo de API da Web é um aplicativo separado do Blazor Web App, possivelmente hospedado em um servidor diferente. -
BlazorApp
/BlazorApp.Client
: Um Blazor Web App que chama a aplicação de API web com um HttpClient para operações da lista de tarefas, como criação, leitura, atualização e exclusão (CRUD) de itens da lista de tarefas.
Para a renderização no lado do cliente (CSR), que inclui componentes Interactive WebAssembly e Auto que adotaram CSR, as chamadas são feitas com um HttpClient pré-configurado e registado no ficheiro Program
do projeto do cliente (BlazorApp.Client
):
builder.Services.AddScoped(sp =>
new HttpClient
{
BaseAddress = new Uri(builder.Configuration["FrontendUrl"] ??
"https://localhost:5002")
});
Para renderização do lado do servidor (SSR), que inclui componentes de servidor pré-renderizados e interativos, componentes WebAssembly pré-renderizados e componentes automáticos que foram pré-renderizados ou adotaram SSR, as chamadas são feitas com um HttpClient registado no ficheiro Program
do projeto de servidor (BlazorApp
):
builder.Services.AddHttpClient();
Chame uma API de lista de filmes interna (dentro do Blazor Web App), onde a API reside no projeto de servidor do Blazor Web App:
-
BlazorApp
: Um Blazor Web App que mantém uma lista de filmes:- Quando as operações são executadas na lista de filmes dentro do aplicativo no servidor, chamadas de API comuns são usadas.
- Quando as chamadas de API são feitas por um cliente baseado na Web, uma API da Web é usada para operações de lista de filmes, com base em APIs mínimas.
-
BlazorApp.Client
: O projeto cliente do Blazor Web App, que contém componentes Interactive WebAssembly e Auto para gestão da lista de filmes pelos utilizadores.
Para CSR, que inclui componentes Interactive WebAssembly e componentes Auto que adotaram CSR, as chamadas para a API são feitas por meio de um serviço baseado em cliente (ClientMovieService
) que usa um HttpClient pré-configurado registrado no arquivo Program
do projeto cliente (BlazorApp.Client
). Como essas chamadas são feitas em uma Web pública ou privada, a API de lista de filmes é uma API da Web .
O exemplo a seguir obtém uma lista de filmes do endpoint /movies
:
public class ClientMovieService(HttpClient http) : IMovieService
{
public async Task<Movie[]> GetMoviesAsync(bool watchedMovies) =>
await http.GetFromJsonAsync<Movie[]>("movies") ?? [];
}
Para SSR, que inclui componentes de servidor interativos e pré-renderizados, componentes WebAssembly pré-renderizados e componentes automáticos pré-renderizados ou que adotaram SSR, as chamadas são feitas diretamente por meio de um serviço baseado em servidor (ServerMovieService
). A API não depende de uma rede, portanto, é uma API padrão para operações CRUD de lista de filmes.
O exemplo a seguir obtém uma lista de filmes:
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 obter mais informações sobre como proteger dados de filmes nesse cenário, consulte o exemplo de dados meteorológicos descrito por Dados seguros em Blazor Web Apps com renderização automática interativa.
BlazorWebAppCallWebApi_Weather
Uma aplicação de exemplo que utiliza renderização por streaming para dados meteorológicos.
BlazorWebAssemblyCallWebApi
Chama uma API Web de lista de tarefas a partir de um aplicativo Blazor WebAssembly:
-
Backend
: Uma aplicação API web para manter uma lista de tarefas, com base em Minimal APIs. -
BlazorTodo
: Uma aplicação Blazor WebAssembly que utiliza a API web com um HttpClient pré-configurado para operações CRUD na lista de tarefas.
BlazorWebAssemblyStandaloneWithIdentity
Uma aplicação de Blazor WebAssembly independente protegida com ASP.NET Core Identity:
-
Backend
: Uma aplicação de API de back-end para a web que mantém um armazenamento de identidade de utilizador para ASP.NET Core Identity. -
BlazorWasmAuth
: Um aplicativo de front-end Blazor WebAssembly autônomo com autenticação de usuário.
A solução demonstra chamar uma API da Web segura para o seguinte:
- Obter funções de um usuário autenticado.
- Processamento de dados para todos os usuários autenticados.
- Processamento de dados para utilizadores autorizados (o utilizador deve estar na função
Manager
) através de uma política de autorização .
BlazorWebAppOidc
Um Blazor Web App com interatividade automática e global que utiliza autenticação OIDC com o Microsoft Entra, sem usar pacotes específicos do Entra. O exemplo demonstra como usar um manipulador de token para chamadas de API da Web para chamar uma API da Web segura externa.
BlazorWebAppOidcServer
A Blazor Web App com interatividade global do Servidor Interativo que usa autenticação OIDC com o Microsoft Entra sem usar pacotes específicos do Entra. O exemplo demonstra como passar um token de acesso para chamar uma API da Web segura externa.
BlazorWebAppOidcBff
Um Blazor Web App com interatividade automática global que utiliza:
- Autenticação OIDC com o Microsoft Entra sem usar pacotes específicos do Entra.
- O padrão Backend for Frontend (BFF), que é um padrão de desenvolvimento de aplicativos que cria serviços de back-end para aplicativos ou interfaces front-end.
A solução inclui uma demonstração da obtenção segura de dados meteorológicos através de uma API web externa quando um componente que adota a renderização automática interativa é renderizado no cliente.
BlazorWebAppEntra
A Blazor Web App com interatividade automática global que usa a plataforma de identidade da Microsoft com pacotes da Web da Microsoft Identity para o Microsoft Entra ID. A solução inclui uma demonstração da obtenção segura de dados meteorológicos através de uma API web externa quando um componente que adota a renderização automática interativa é renderizado no cliente.
BlazorWebAppEntraBff
Um Blazor Web App com interatividade automática global que utiliza:
- Plataforma de identidade da Microsoft com os pacotes Web da Microsoft Identity para o Microsoft Entra ID.
- O padrão Backend for Frontend (BFF), que é um padrão de desenvolvimento de aplicativos que cria serviços de back-end para aplicativos ou interfaces front-end.
A solução inclui uma demonstração da obtenção segura de dados meteorológicos através de uma API web externa quando um componente que adota a renderização automática interativa é renderizado no cliente.
Eliminação de HttpRequestMessage
, HttpResponseMessage
e HttpClient
Um HttpRequestMessage sem corpo não requer eliminação explícita com uma using
declaração (C# 8 ou posterior) ou um using
bloco (todas as versões C#), mas recomendamos realizar a eliminação após cada utilização pelos seguintes motivos:
- Para melhorar o desempenho ao evitar o uso de finalizadores.
- Ele endurece o código para o futuro, caso um corpo de solicitação seja adicionado a um HttpRequestMessage que inicialmente não tinha um.
- Para evitar potencialmente problemas funcionais, caso um manipulador delegante espere uma chamada para Dispose/DisposeAsync.
- É mais simples aplicar uma regra geral em todos os lugares do que tentar lembrar casos específicos.
Descarte sempre as HttpResponseMessage instâncias.
Nunca descarte HttpClient instâncias criadas por chamada CreateClient porque elas são gerenciadas pela estrutura.
Exemplo:
using var request = new HttpRequestMessage(HttpMethod.Get, "/weather-forecast");
var client = clientFactory.CreateClient("ExternalApi");
using var response = await client.SendAsync(request);
Cenários do lado do cliente para chamar APIs da Web externas
Os componentes baseados em cliente chamam APIs da Web externas usando instâncias HttpClient, normalmente criadas com um HttpClient pré-configurado registrado no arquivo Program
:
builder.Services.AddScoped(sp =>
new HttpClient
{
BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
});
O componente seguinte Razor faz uma solicitação a uma API web para branches do GitHub, semelhante ao exemplo de Uso Básico no artigo Fazer solicitações HTTP usando IHttpClientFactory no 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; }
}
}
No exemplo anterior para C# 12 ou posterior, uma matriz vazia ([]
) é criada para a variável branches
. Para versões anteriores do C# compiladas com um SDK anterior ao .NET 8, crie uma matriz vazia (Array.Empty<GitHubBranch>()
).
Para proteger o código e os dados do .NET/C#, use os recursos do ASP.NET Core Data Protection com uma API da Web de back-end ASP.NET Core do lado do servidor. O aplicativo Blazor WebAssembly do lado do cliente chama a API da Web do lado do servidor para recursos seguros do aplicativo e processamento de dados.
Blazor WebAssembly os aplicativos geralmente são impedidos de fazer chamadas diretas entre origens para APIs da Web devido à segurança do CORS (Cross-Origin Request Sharing). Uma exceção típica tem a seguinte aparência:
Acesso para buscar em '{URL}' da origem 'https://localhost:{PORT}'' foi bloqueado pela política CORS: Nenhum cabeçalho 'Access-Control-Allow-Origin' está presente no recurso solicitado. Se uma resposta opaca atender às suas necessidades, defina o modo da solicitação como 'no-cors' para buscar o recurso com o CORS desativado.
Mesmo que chames SetBrowserRequestMode com um campo BrowserRequestMode de NoCors
(1) na tentativa de contornar a exceção anterior, o pedido falha frequentemente devido a restrições CORS na origem da API da Web, como uma restrição que apenas permite chamadas de origens específicas ou uma restrição que impede solicitações JavaScript fetch
de um navegador. A única maneira de essas chamadas serem bem-sucedidas é que a API da Web que você está chamando permita que sua origem chame sua origem com a configuração CORS correta. A maioria das APIs da Web externas não permite que você configure suas políticas de CORS. Para lidar com essa restrição, adote uma das seguintes estratégias:
Mantenha o seu próprio backend web API ASP.NET Core no servidor. O aplicativo Blazor WebAssembly do lado do cliente chama sua API da Web do lado do servidor e sua API da Web faz a solicitação de seu código C# baseado em servidor (não um navegador) para a API da Web externa com os cabeçalhos CORS corretos, retornando o resultado para seu aplicativo Blazor WebAssembly do lado do cliente.
Utilize um serviço de proxy para encaminhar a solicitação do aplicativo Blazor WebAssembly do cliente para a API web externa. O serviço de proxy usa um aplicativo do lado do servidor para fazer a solicitação em nome do cliente e retorna o resultado depois que a chamada é bem-sucedida. No exemplo a seguir baseado no CloudFlare's CORS PROXY, o
{REQUEST URI}
marcador de posição é o URI da solicitação:@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); ... } }
Cenários do lado do servidor para chamar APIs da Web externas
Os componentes baseados em servidor chamam APIs da Web externas usando instâncias HttpClient, normalmente criadas usando IHttpClientFactory. Para obter orientações que se aplicam a aplicativos do lado do servidor, consulte Fazer solicitações HTTP usando IHttpClientFactory no ASP.NET Core.
Um aplicativo do lado do servidor não inclui um serviço HttpClient. Forneça um HttpClient para a aplicação usando a HttpClient
infraestrutura de fábrica.
No ficheiro Program
:
builder.Services.AddHttpClient();
O componente seguinte Razor faz uma solicitação a uma API web para branches do GitHub, semelhante ao exemplo de Uso Básico no artigo Fazer solicitações HTTP usando IHttpClientFactory no 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; }
}
}
No exemplo anterior para C# 12 ou posterior, uma matriz vazia ([]
) é criada para a variável branches
. Para versões anteriores do C# compiladas com um SDK anterior ao .NET 8, crie uma matriz vazia (Array.Empty<GitHubBranch>()
).
Para obter um exemplo de trabalho adicional, consulte o exemplo de carregamento de arquivo do lado do servidor que carrega arquivos para um controlador de API da Web no artigo Carregamentos de arquivos ASP.NET CoreBlazor.
Abstrações de serviço para chamadas de API da Web
Esta seção se aplica a Blazor Web Apps que mantêm uma API da Web no projeto do servidor ou transformam chamadas de API da Web em uma API da Web externa.
Ao usar os modos interativos WebAssembly e Auto renderização, os componentes são pré-renderizados por padrão. Os componentes do sistema também são inicialmente renderizados interativamente a partir do servidor antes que o bundle Blazor seja transferido para o cliente e a execução no lado do cliente seja ativada. Isso significa que os componentes que usam esses modos de renderização devem ser projetados para que sejam executados com êxito a partir do cliente e do servidor. Se o componente precisar chamar uma API baseada em projeto de servidor ou transformar uma solicitação em uma API da Web externa (que esteja fora do Blazor Web App) durante a execução no cliente, a abordagem recomendada é abstrair essa chamada de API por trás de uma interface de serviço e implementar versões de cliente e servidor do serviço:
- A versão do cliente chama a API web com um HttpClientpré-configurado.
- A versão do servidor normalmente pode acessar os recursos do lado do servidor diretamente. Não é recomendável injetar um HttpClient no servidor que faz chamadas de volta para o servidor, pois a solicitação de rede normalmente é desnecessária. Como alternativa, a API pode ser externa ao projeto do servidor, mas uma abstração de serviço para o servidor é necessária para transformar a solicitação de alguma forma, por exemplo, para adicionar um token de acesso a uma solicitação por proxy.
Ao usar o modo de renderização WebAssembly, você também tem a opção de desabilitar a pré-renderização, para que os componentes só sejam renderizados a partir do cliente. Para obter mais informações, consulte Modos de renderização ASP.NET CoreBlazor.
Exemplos (aplicativos de exemplo):
- API Web de lista de filmes no aplicativo de exemplo
BlazorWebAppCallWebApi
. - API Web de renderização em fluxo contínuo de dados meteorológicos no aplicativo de exemplo
BlazorWebAppCallWebApi_Weather
. - Os dados meteorológicos são retornados ao cliente nos aplicativos de exemplo
BlazorWebAppOidc
(padrão não BFF) ouBlazorWebAppOidcBff
(padrão BFF). Esses aplicativos demonstram chamadas de API (web) seguras. Para obter mais informações, consulte Proteger um ASP.NET Core Blazor Web App com OpenID Connect (OIDC).
Blazor Web App APIs externas da web
Esta seção se aplica a Blazor Web Apps que chamam uma API da Web mantida por um projeto separado (externo), possivelmente hospedado em um servidor diferente.
Blazor Web Apps normalmente pré-renderizam componentes WebAssembly do lado do cliente, e componentes Auto são renderizados no servidor durante a renderização estática ou interativa do lado do servidor (SSR). Os serviços de HttpClient não são registados por padrão no projeto principal de um Blazor Web App. Se o aplicativo for executado apenas com os HttpClient serviços registrados no .Client
projeto, conforme descrito na seção Adicionar o HttpClient
serviço , a execução do aplicativo resultará em um erro de tempo de execução:
InvalidOperationException: Não é possível fornecer um valor para a propriedade 'Http' no tipo '... {COMPONENTE}'. Não existe nenhum serviço registado do tipo 'System.Net.Http.HttpClient'.
Use uma das seguintes abordagens:
Adicione os serviços HttpClient ao projeto de servidor para disponibilizar o HttpClient durante o SSR. Use o seguinte registro de serviço no arquivo de
Program
do projeto de servidor:builder.Services.AddHttpClient();
HttpClient serviços são fornecidos pela estrutura compartilhada, portanto, uma referência de pacote no arquivo de projeto do aplicativo não é necessária.
Exemplo: Toda list web API no aplicativo de exemplo
BlazorWebAppCallWebApi
Se a pré-renderização não for necessária para um componente WebAssembly que chama a API da Web, desative a pré-renderização seguindo as orientações nos modos de renderização ASP.NET CoreBlazor. Se adotar esta abordagem, não precisará adicionar os serviços HttpClient ao projeto principal do Blazor Web App porque o componente não é pré-renderizado no servidor.
Para obter mais informações, consulte Os serviços do lado do cliente falham em resolver durante a pré-renderização.
Dados pré-renderizados
Durante a pré-renderização, os componentes são renderizados duas vezes: primeiro estaticamente, depois interativamente. O estado não flui automaticamente do componente pré-renderizado para o interativo. Se um componente executar operações de inicialização assíncronas e renderizar conteúdo diferente para estados diferentes durante a inicialização, como um "Carregando..." indicador de progresso, você pode ver uma cintilação quando o componente renderiza duas vezes.
Pode resolver esta questão ao propagar o estado pré-renderizado utilizando a API de Estado Persistente do Componente, como demonstrado pelas aplicações de exemplo BlazorWebAppCallWebApi
e BlazorWebAppCallWebApi_Weather
. Quando o componente é renderizado interativamente, ele pode renderizar da mesma maneira usando o mesmo estado. No entanto, a API atualmente não funciona com navegação aprimorada, que você pode contornar desativando a navegação aprimorada em links para a página (data-enhanced-nav=false
). Para obter mais informações, consulte os seguintes recursos:
Streaming de solicitações do cliente
Para navegadores baseados no Chromium (por exemplo, Google Chrome e Microsoft Edge) que usam o protocolo HTTP/2 e HTTPS, o lado do cliente Blazor usa a API do Streams para permitir o streaming de solicitações.
Para habilitar o streaming de solicitações, configure SetBrowserRequestStreamingEnabled para true
no HttpRequestMessage.
No seguinte exemplo de upload de arquivo:
-
content
é o HttpContentdo arquivo. -
/Filesave
é o endpoint da API web. -
Http
é o HttpClient.
using var request = new HttpRequestMessage(HttpMethod.Post, "/Filesave");
request.SetBrowserRequestStreamingEnabled(true);
request.Content = content;
using var response = await Http.SendAsync(request);
Pedidos de streaming:
- Requer protocolo HTTPS e não funciona em HTTP/1.x.
- Inclua um corpo, mas não um cabeçalho
Content-Length
. CORS com uma solicitação de preflight é necessário para as solicitações de streaming de origem cruzada.
Para obter mais informações sobre o carregamento de arquivos com um componente InputFile, consulte carregamento de arquivos no ASP.NET Core Blazor e o exemplo em Carregar arquivos para um servidor com renderização do lado do cliente (CSR).
Adicionar o serviço HttpClient
As orientações nesta seção se aplicam a cenários do lado do cliente.
Os componentes do lado do cliente chamam APIs da Web usando um serviço HttpClient pré-configurado, que se concentra em fazer solicitações de volta ao servidor de origem. Configurações de serviço de HttpClient adicionais para outras APIs da Web podem ser criadas no código do desenvolvedor. As solicitações são compostas usando Blazor auxiliares JSON ou com HttpRequestMessage. As solicitações podem incluir a configuração da opção Fetch API.
Os exemplos de configuração nesta seção só são úteis quando uma única API da Web é chamada para uma única instância de HttpClient no aplicativo. Quando o aplicativo precisa chamar várias APIs da Web, cada uma com seu próprio endereço base e configuração, você pode adotar as seguintes abordagens, que serão abordadas mais adiante neste artigo:
-
Nomeado
HttpClient
comIHttpClientFactory
: Cada API da Web recebe um nome exclusivo. Quando o código do aplicativo ou um componente Razor chama uma API da Web, ele usa uma instância de HttpClient nomeada para fazer a chamada. -
Digitado
HttpClient
: Cada API da Web é digitada. Quando o código do aplicativo ou um componente Razor chama uma API da Web, ele usa uma instância de HttpClient digitada para fazer a chamada.
No arquivo Program
, adicione um serviço de HttpClient se ele ainda não estiver presente em um modelo de projeto Blazor usado para criar o aplicativo:
builder.Services.AddScoped(sp =>
new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
O exemplo anterior define o endereço base com builder.HostEnvironment.BaseAddress
(IWebAssemblyHostEnvironment.BaseAddress), que obtém o endereço base para o aplicativo e normalmente é derivado do valor <base>
da tag href
na página de host.
Os casos de uso mais comuns para usar o endereço base do próprio cliente são:
- O projeto cliente (
.Client
) de um Blazor Web App (.NET 8 ou posterior) faz chamadas de API web a partir de componentes ou códigos WebAssembly que são executados no cliente, para as APIs no aplicativo de servidor. - O projeto cliente (Client) de um aplicativo de Blazor WebAssembly hospedado faz chamadas de API da Web para o projeto de servidor (Server). Observe que o modelo de projeto Hosted Blazor WebAssembly não está mais disponível no .NET 8 ou posterior. No entanto, os aplicativos de Blazor WebAssembly hospedados permanecem com suporte para o .NET 8.
Se você estiver chamando uma API da Web externa (não no mesmo espaço de URL do aplicativo cliente), defina o URI como o endereço base da API da Web. O exemplo a seguir define o endereço base da API da Web como https://localhost:5001
, onde um aplicativo de API da Web separado está em execução e pronto para responder às solicitações do aplicativo cliente:
builder.Services.AddScoped(sp =>
new HttpClient { BaseAddress = new Uri("https://localhost:5001") });
Ferramentas JSON
HttpClient está disponível como um serviço pré-configurado para fazer solicitações de volta ao servidor de origem.
HttpClient e auxiliares JSON (System.Net.Http.Json.HttpClientJsonExtensions) também são usados para chamar endpoints de APIs web de terceiros. HttpClient é implementado usando a API Fetch do navegador e está sujeito às suas limitações, incluindo a aplicação da política de mesma origem, que é discutida mais adiante neste artigo na seção Cross-Origin Resource Sharing (CORS)
O endereço base do cliente é definido como o endereço do servidor de origem. Injete uma instância HttpClient em um componente usando a diretiva @inject
:
@using System.Net.Http
@inject HttpClient Http
Use o namespace System.Net.Http.Json para acessar HttpClientJsonExtensions, incluindo GetFromJsonAsync, PutAsJsonAsynce PostAsJsonAsync:
@using System.Net.Http.Json
As seções a seguir abrangem os auxiliares JSON:
System.Net.Http inclui métodos adicionais para enviar solicitações HTTP e receber respostas HTTP, por exemplo, para enviar uma solicitação DELETE. Para obter mais informações, consulte a seção DELETE e métodos de extensão adicionais .
Obter a partir de JSON (GetFromJsonAsync
)
GetFromJsonAsync envia uma solicitação HTTP GET e analisa o corpo da resposta JSON para criar um objeto.
No código do componente a seguir, os todoItems
são exibidos pelo componente.
GetFromJsonAsync é chamado quando o componente termina de inicializar (OnInitializedAsync
).
todoItems = await Http.GetFromJsonAsync<TodoItem[]>("todoitems");
POST em JSON (PostAsJsonAsync
)
PostAsJsonAsync envia uma solicitação POST para o URI especificado contendo o valor serializado como JSON no corpo da solicitação.
No código do componente a seguir, newItemName
é fornecido por um elemento ligado do componente. O método AddItem
é acionado pela seleção de um elemento <button>
.
await Http.PostAsJsonAsync("todoitems", addItem);
PostAsJsonAsync retorna um HttpResponseMessage. Para desserializar o conteúdo JSON da mensagem de resposta, use o método de extensão ReadFromJsonAsync. O exemplo a seguir lê dados meteorológicos JSON como uma matriz:
var content = await response.Content.ReadFromJsonAsync<WeatherForecast[]>() ??
Array.Empty<WeatherForecast>();
PUT como JSON (PutAsJsonAsync
)
PutAsJsonAsync envia uma solicitação HTTP PUT com conteúdo codificado em JSON.
No seguinte código do componente, os valores de editItem
para Name
e IsCompleted
são fornecidos por elementos vinculados do componente. O Id
do item é definido quando o item é selecionado em outra parte da interface de utilizador (não visível) e EditItem
é chamado. O método SaveItem
é acionado selecionando o elemento <button>
. O exemplo a seguir não mostra o carregamento de todoItems
para simplificar. Consulte a seção GET de JSON (GetFromJsonAsync
) para obter um exemplo de carregamento de itens.
await Http.PutAsJsonAsync($"todoitems/{editItem.Id}", editItem);
PutAsJsonAsync retorna um HttpResponseMessage. Para desserializar o conteúdo JSON da mensagem de resposta, use o método de extensão ReadFromJsonAsync. O exemplo a seguir lê dados meteorológicos JSON como uma matriz:
var content = await response.Content.ReadFromJsonAsync<WeatherForecast[]>() ??
Array.Empty<WeatherForecast>();
PATCH como JSON (PatchAsJsonAsync
)
PatchAsJsonAsync envia uma solicitação HTTP PATCH com conteúdo codificado em JSON.
Observação
Para obter mais informações, consulte JsonPatch em ASP.NET Core Web API.
No exemplo a seguir, PatchAsJsonAsync recebe um documento JSON PATCH como uma string de texto simples, com aspas escapadas:
await Http.PatchAsJsonAsync(
$"todoitems/{id}",
"[{\"operationType\":2,\"path\":\"/IsComplete\",\"op\":\"replace\",\"value\":true}]");
A partir do C# 11 (.NET 7), você pode compor uma cadeia de caracteres JSON como uma cadeia de caracteres bruta literal. Especifique a sintaxe JSON com o StringSyntaxAttribute.Json campo para o [StringSyntax]
atributo para ferramentas de análise 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 retorna um HttpResponseMessage. Para desserializar o conteúdo JSON da mensagem de resposta, use o método de extensão ReadFromJsonAsync. O exemplo a seguir lê JSON todo item data como uma matriz. Uma matriz vazia é criada se nenhum dado de item for retornado pelo método, para que content
não seja nulo depois que a instrução for executada:
using var response = await Http.PatchAsJsonAsync(...);
var content = await response.Content.ReadFromJsonAsync<TodoItem[]>() ??
Array.Empty<TodoItem>();
Formatado com indentações, espaços e aspas sem escape, o documento PATCH não codificado aparece como o seguinte JSON.
[
{
"operationType": 2,
"path": "/IsComplete",
"op": "replace",
"value": true
}
]
Para simplificar a criação de documentos PATCH no aplicativo que emite solicitações PATCH, um aplicativo pode usar o suporte a .NET JSON PATCH, como demonstra a orientação a seguir.
Instale o pacote NuGet Microsoft.AspNetCore.JsonPatch.SystemTextJson
e use os recursos de API do pacote para compor um JsonPatchDocument
para uma solicitação PATCH.
Observação
Para obter orientação sobre como adicionar pacotes a aplicativos .NET, consulte os artigos em Instalar e gerenciar pacotes em Fluxo de trabalho de consumo de pacotes (documentação do NuGet). Confirme as versões corretas do pacote em NuGet.org.
Adicione diretivas @using
para os namespaces System.Text.Json, System.Text.Json.Serialization, Microsoft.AspNetCore.JsonPatch.SystemTextJson
e na parte superior do componente Razor.
@using System.Text.Json
@using System.Text.Json.Serialization
@using Microsoft.AspNetCore.JsonPatch.SystemTextJson
Componha o JsonPatchDocument
de um TodoItem
com IsComplete
definido como true
usando o método JsonPatchDocument.Replace
:
var patchDocument = new JsonPatchDocument<TodoItem>()
.Replace(p => p.IsComplete, true);
Instale o pacote NuGet Microsoft.AspNetCore.JsonPatch
e use os recursos de API do pacote para compor um JsonPatchDocument para uma solicitação PATCH.
Observação
Para obter orientação sobre como adicionar pacotes a aplicativos .NET, consulte os artigos em Instalar e gerenciar pacotes em Fluxo de trabalho de consumo de pacotes (documentação do NuGet). Confirme as versões corretas do pacote em NuGet.org.
Adicione diretivas @using
para os namespaces System.Text.Json, System.Text.Json.Serializatione Microsoft.AspNetCore.JsonPatch no topo do componente Razor.
@using System.Text.Json
@using System.Text.Json.Serialization
@using Microsoft.AspNetCore.JsonPatch
Componha o JsonPatchDocument de um TodoItem
com IsComplete
definido como true
usando o método Replace:
var patchDocument = new JsonPatchDocument<TodoItem>()
.Replace(p => p.IsComplete, true);
Passe as operações do documento (patchDocument.Operations
) para a chamada PatchAsJsonAsync:
private async Task UpdateItem(long id)
{
await Http.PatchAsJsonAsync(
$"todoitems/{id}",
patchDocument.Operations,
new JsonSerializerOptions()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault
});
}
JsonSerializerOptions.DefaultIgnoreCondition é definido para JsonIgnoreCondition.WhenWritingDefault para ignorar uma propriedade apenas se ela for igual ao valor padrão para o seu tipo.
Adicione JsonSerializerOptions.WriteIndented definido como true
se quiser apresentar a carga JSON num formato visual agradável. A escrita de JSON com indentação não afeta o processamento de pedidos PATCH e normalmente não é realizada em aplicações de produção para pedidos de API web.
Siga as orientações no artigo JsonPatch na API da Web ASP.NET Core para adicionar uma ação do controlador PATCH à API da Web. Como alternativa, o processamento de solicitações PATCH pode ser implementado como uma API mínima com as etapas a seguir.
Adicione uma referência de pacote para o pacote NuGet Microsoft.AspNetCore.JsonPatch.SystemTextJson
ao aplicativo de API Web.
No ficheiro Program
, adicione uma diretiva @using
para o namespace Microsoft.AspNetCore.JsonPatch.SystemTextJson
.
using Microsoft.AspNetCore.JsonPatch.SystemTextJson;
Adicione uma referência de pacote para o pacote NuGet Microsoft.AspNetCore.Mvc.NewtonsoftJson
ao aplicativo de API Web.
Observação
Não há necessidade de adicionar uma referência de pacote para o pacote Microsoft.AspNetCore.JsonPatch
ao aplicativo porque a referência ao pacote Microsoft.AspNetCore.Mvc.NewtonsoftJson
adiciona automaticamente uma referência de pacote para Microsoft.AspNetCore.JsonPatch
.
No arquivo Program
adicione uma diretiva @using
para o namespace Microsoft.AspNetCore.JsonPatch:
using Microsoft.AspNetCore.JsonPatch;
Forneça o endpoint para o pipeline de processamento de solicitações da 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();
});
Advertência
Como nos outros exemplos no artigo JsonPatch in ASP.NET Core web API, a PATCH API mencionada não protege a API web contra ataques de postagem excessiva. Para obter mais informações, consulte Tutorial: Criar uma API da Web baseada em controlador com o ASP.NET Core.
Para uma experiência PATCH totalmente funcional, consulte a aplicação de exemplo BlazorWebAppCallWebApi
.
DELETE (DeleteAsync
) e métodos de extensão adicionais
System.Net.Http inclui métodos de extensão adicionais para enviar solicitações HTTP e receber respostas HTTP. HttpClient.DeleteAsync é usado para enviar uma solicitação HTTP DELETE para uma API da Web.
No código de componente a seguir, o elemento <button>
chama o método DeleteItem
. O elemento <input>
vinculado fornece o id
do item a ser removido.
await Http.DeleteAsync($"todoitems/{id}");
Nomeado HttpClient
com IHttpClientFactory
Os serviços de IHttpClientFactory e a configuração de um HttpClient nomeado são suportados.
Observação
Uma alternativa ao uso de um HttpClient nomeado proveniente de um IHttpClientFactory é usar um HttpClient tipado. Para obter mais informações, consulte a seção Especificado HttpClient
.
Adicione o pacote NuGet Microsoft.Extensions.Http
à aplicação.
Observação
Para obter orientação sobre como adicionar pacotes a aplicativos .NET, consulte os artigos em Instalar e gerenciar pacotes em Fluxo de trabalho de consumo de pacotes (documentação do NuGet). Confirme as versões corretas do pacote em NuGet.org.
No arquivo Program
de um projeto cliente:
builder.Services.AddHttpClient("WebAPI", client =>
client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress));
Se o cliente nomeado for utilizado por componentes pré-renderizados no lado cliente de um Blazor Web App, o registo de serviço previamente mencionado deverá constar tanto no projeto do servidor como no projeto .Client
. No servidor, builder.HostEnvironment.BaseAddress
é substituído pelo endereço base da API da Web, que é descrito mais abaixo.
O exemplo anterior do lado do cliente define o endereço base com builder.HostEnvironment.BaseAddress
(IWebAssemblyHostEnvironment.BaseAddress), que obtém o endereço base para o aplicativo do lado do cliente e normalmente é derivado do valor <base>
da tag href
na página do host.
Os casos de uso mais comuns para usar o endereço base do próprio cliente são:
- O projeto cliente (
.Client
) de um Blazor Web App que faz chamadas para APIs da web a partir de componentes em WebAssembly/Auto, ou código executado no cliente em WebAssembly, para as APIs no aplicativo do servidor no mesmo endereço de host. - O projeto cliente (Client) de uma aplicação hospedada Blazor WebAssembly que faz chamadas à API web para o projeto servidor (Server).
O caso de uso mais comum para usar o endereço base próprio do cliente está no projeto cliente (Client) de um aplicativo hospedado Blazor WebAssembly que faz chamadas de API da Web para o projeto de servidor (Server).
Se você estiver chamando uma API da Web externa (não no mesmo espaço de URL do aplicativo cliente) ou estiver configurando os serviços em um aplicativo do lado do servidor (por exemplo, para lidar com a pré-renderização de componentes do lado do cliente no servidor), defina o URI como o endereço base da API da Web. O exemplo a seguir define o endereço base da API da Web como https://localhost:5001
, onde um aplicativo de API da Web separado está em execução e pronto para responder às solicitações do aplicativo cliente:
builder.Services.AddHttpClient("WebAPI", client =>
client.BaseAddress = new Uri("https://localhost:5001"));
No seguinte código de componente:
- Uma instância de IHttpClientFactory cria um nome HttpClient.
- A variável HttpClient é usada para emitir uma solicitação GET para obter dados JSON de previsão do tempo da API web em
/forecast
.
@inject IHttpClientFactory ClientFactory
...
@code {
private Forecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
var client = ClientFactory.CreateClient("WebAPI");
forecasts = await client.GetFromJsonAsync<Forecast[]>("forecast") ?? [];
}
}
O aplicativo de exemplo BlazorWebAppCallWebApi
demonstra como chamar uma API da Web com um item HttpClient nomeado no seu componente CallTodoWebApiCsrNamedClient
. Para obter uma demonstração de trabalho adicional em um aplicativo cliente com base na chamada do Microsoft Graph com um nome HttpClient, consulte Usar a API do Graph com ASP.NET Core Blazor WebAssembly.
Para obter uma demonstração de trabalho em um aplicativo cliente com base na chamada do Microsoft Graph com um nome HttpClient, consulte Usar a API do Graph com o ASP.NET Core Blazor WebAssembly.
Inserido HttpClient
O tipo HttpClient usa uma ou mais instâncias HttpClient do aplicativo, padrão ou nomeadas, para retornar dados de um ou mais endpoints da API web.
Observação
Uma alternativa ao uso de um HttpClient específico é usar um HttpClient nomeado a partir de um IHttpClientFactory. Para obter mais informações, consulte a seção Nome HttpClient
com IHttpClientFactory
.
Adicione o pacote NuGet Microsoft.Extensions.Http
à aplicação.
Observação
Para obter orientação sobre como adicionar pacotes a aplicativos .NET, consulte os artigos em Instalar e gerenciar pacotes em Fluxo de trabalho de consumo de pacotes (documentação do NuGet). Confirme as versões corretas do pacote em NuGet.org.
O exemplo seguinte faz uma solicitação GET para obter dados de previsão do tempo em JSON da Web API em /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") ?? [];
}
No arquivo Program
de um projeto cliente:
builder.Services.AddHttpClient<ForecastHttpClient>(client =>
client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress));
Se o cliente tipado for usado por componentes cliente pré-renderizados de Blazor Web App, o registo de serviço anterior deverá aparecer no projeto do servidor e no projeto .Client
. No servidor, builder.HostEnvironment.BaseAddress
é substituído pelo endereço base da API da Web, que é descrito mais abaixo.
O exemplo anterior define o endereço base com builder.HostEnvironment.BaseAddress
(IWebAssemblyHostEnvironment.BaseAddress), que obtém o endereço base para o aplicativo do lado do cliente e normalmente é derivado do valor <base>
da tag href
na página do host.
Os casos de uso mais comuns para usar o endereço base do próprio cliente são:
- O projeto cliente (
.Client
) de um Blazor Web App que faz chamadas para APIs da web a partir de componentes em WebAssembly/Auto, ou código executado no cliente em WebAssembly, para as APIs no aplicativo do servidor no mesmo endereço de host. - O projeto cliente (Client) de uma aplicação hospedada Blazor WebAssembly que faz chamadas à API web para o projeto servidor (Server).
O caso de uso mais comum para usar o endereço base próprio do cliente está no projeto cliente (Client) de um aplicativo hospedado Blazor WebAssembly que faz chamadas de API da Web para o projeto de servidor (Server).
Se você estiver chamando uma API da Web externa (não no mesmo espaço de URL do aplicativo cliente) ou estiver configurando os serviços em um aplicativo do lado do servidor (por exemplo, para lidar com a pré-renderização de componentes do lado do cliente no servidor), defina o URI como o endereço base da API da Web. O exemplo a seguir define o endereço base da API da Web como https://localhost:5001
, onde um aplicativo de API da Web separado está em execução e pronto para responder às solicitações do aplicativo cliente:
builder.Services.AddHttpClient<ForecastHttpClient>(client =>
client.BaseAddress = new Uri("https://localhost:5001"));
Os componentes injetam o objeto tipado HttpClient para chamar a API da Web.
No seguinte código de componente:
- Uma instância do
ForecastHttpClient
anterior é injetada, o que cria uma HttpClient tipificada. - O HttpClient digitado é usado para emitir uma solicitação GET para dados JSON de previsão do tempo da API web.
@inject ForecastHttpClient Http
...
@code {
private Forecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
forecasts = await Http.GetForecastAsync();
}
}
A aplicação de exemplo BlazorWebAppCallWebApi
demonstra a invocação de uma API web com um HttpClient tipado no seu componente CallTodoWebApiCsrTypedClient
. Observe que o componente adota a renderização do lado do cliente (CSR) (InteractiveWebAssembly
modo de renderização) com pré-renderização, portanto, o registo de serviço de cliente tipificado aparece no Program
arquivo do projeto do servidor e do .Client
projeto.
Credenciais de solicitação baseadas em Cookie
As orientações nesta seção se aplicam a cenários do lado do cliente que dependem de uma autenticação cookie.
Para a autenticação baseada em cookie, que é considerada mais segura do que a autenticação de token de portador, as credenciais cookie podem ser enviadas com cada solicitação de API web chamando AddHttpMessageHandler com um DelegatingHandler num HttpClient pré-configurado. O manipulador configura SetBrowserRequestCredentials com BrowserRequestCredentials.Include, que aconselha o navegador a enviar credenciais com cada solicitação, como cookies ou cabeçalhos de autenticação HTTP, inclusive para solicitações de origem cruzada.
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);
}
}
Observação
Para obter orientação sobre como aceder a um AuthenticationStateProvider
de um DelegatingHandler
, consulte ASP.NET Core do lado do servidor e Blazor Web App cenários de segurança adicionais.
O CookieHandler
está registado no ficheiro Program
:
builder.Services.AddTransient<CookieHandler>();
O manipulador de mensagens é adicionado a qualquer HttpClient preconfigurado que necessite de autenticação cookie:
builder.Services.AddHttpClient(...)
.AddHttpMessageHandler<CookieHandler>();
Para uma demonstração, consulte Segurança no ASP.NET Core Blazor WebAssembly com ASP.NET Core Identity.
Ao compor um HttpRequestMessage, defina as credenciais de solicitação do navegador e o cabeçalho diretamente:
using var request = new HttpRequestMessage() { ... };
request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);
request.Headers.Add("X-Requested-With", [ "XMLHttpRequest" ]);
HttpClient
e HttpRequestMessage
com as opções de solicitação da Fetch API
As orientações nesta seção se aplicam a cenários do lado do cliente que dependem da autenticação de token de portador.
HttpClient
(documentação da API) e HttpRequestMessage pode ser usado para personalizar solicitações. Por exemplo, você pode especificar o método HTTP e cabeçalhos de solicitação. O componente seguinte faz uma solicitação POST
a um endpoint da API web e mostra o corpo da resposta.
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; }
}
}
Blazorimplementação do lado do cliente do HttpClient usa a API de busca e configura as opções de API de busca subjacentes específicas para pedidos através de métodos de extensão HttpRequestMessage e WebAssemblyHttpRequestMessageExtensions. Defina opções adicionais usando o método de extensão SetBrowserRequestOption genérico. Blazor e a API de busca subjacente não adicionam ou modificam diretamente cabeçalhos de solicitação. Para obter mais informações sobre como os agentes de usuário, como navegadores, interagem com cabeçalhos, consulte conjuntos de documentação de agentes de usuário externos e outros recursos da Web.
O streaming de resposta está habilitado por padrão.
Chamar HttpContent.ReadAsStreamAsync para um HttpResponseMessage.Content (response.Content.ReadAsStreamAsync()
) retorna uma BrowserHttpReadStream
(fonte de referência), não um MemoryStream.
BrowserHttpReadStream
não oferece suporte a operações síncronas, como Stream.Read(Span<Byte>)
. Se o seu código usa operações síncronas, você pode desativar o streaming de respostas ou copiar o Stream para um MemoryStream você mesmo.
Observação
Os links de documentação para a fonte de referência do .NET geralmente carregam a ramificação padrão do repositório, que representa o desenvolvimento atual para a próxima versão do .NET. Para selecionar uma tag para uma versão específica, use a lista suspensa Alternar entre ramificações ou tags. Para obter mais informações, consulte Como selecionar uma marca de versão do código-fonte ASP.NET Core (dotnet/AspNetCore.Docs #26205).
Para desativar o streaming de respostas globalmente, use uma das seguintes abordagens:
Adicione a
<WasmEnableStreamingResponse>
propriedade ao arquivo de projeto com um valor defalse
:<WasmEnableStreamingResponse>false</WasmEnableStreamingResponse>
Defina a
DOTNET_WASM_ENABLE_STREAMING_RESPONSE
variável de ambiente comofalse
ou0
.
Para desativar o streaming de resposta para uma solicitação individual, defina SetBrowserResponseStreamingEnabled como false
no HttpRequestMessage (request
no exemplo a seguir):
request.SetBrowserResponseStreamingEnabled(false);
A resposta HTTP normalmente é armazenada em buffer para habilitar o suporte para leituras síncronas no conteúdo da resposta. Para habilitar o suporte para streaming de respostas, defina SetBrowserResponseStreamingEnabled como true
no HttpRequestMessage:
request.SetBrowserResponseStreamingEnabled(true);
Por padrão, HttpCompletionOption.ResponseContentRead
está configurado, o que faz com que o HttpClient seja concluído após a leitura de toda a resposta, incluindo o conteúdo. Para poder usar a opção SetBrowserResponseStreamingEnabled em arquivos grandes, defina HttpCompletionOption.ResponseHeadersRead
para evitar o armazenamento em cache do conteúdo do arquivo na memória:
- using var response = await Http.SendAsync(request);
+ using var response = await Http.SendAsync(request,
+ HttpCompletionOption.ResponseHeadersRead);
Para incluir credenciais em uma solicitação de origem cruzada, use o método de extensão SetBrowserRequestCredentials:
request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);
Para obter mais informações sobre as opções da API de busca, consulte MDN web docs: WindowOrWorkerGlobalScope.fetch(): Parameters.
Lidar com erros
Trate os erros de resposta da API da Web no código dos desenvolvedores quando ocorrem. Por exemplo, GetFromJsonAsync espera uma resposta JSON da API web com um Content-Type
de application/json
. Se a resposta não estiver no formato JSON, a validação de conteúdo lançará um NotSupportedException.
No exemplo a seguir, o endpoint URI para a solicitação de dados da previsão do tempo está escrito erroneamente. O URI deveria ser para WeatherForecast
, mas aparece na chamada como WeatherForcast
, faltando o caracter e
em Forecast
.
A chamada GetFromJsonAsync espera que um JSON seja retornado, mas a API da Web retorna HTML como resposta a uma exceção não tratada com um Content-Type
com valor de text/html
. A exceção não tratada ocorre porque o caminho para /WeatherForcast
não foi encontrado e o middleware não pode servir uma página ou exibição para a solicitação.
Em OnInitializedAsync no cliente, NotSupportedException é gerado quando o conteúdo da resposta é validado como algo que não é JSON. A exceção é capturada no bloco catch
, onde a lógica personalizada pode registrar o erro ou apresentar uma mensagem de erro amigável ao usuário.
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;
}
}
}
Observação
O exemplo anterior é para fins de demonstração. Uma API da Web pode ser configurada para retornar JSON mesmo quando um ponto de extremidade não existe ou ocorre uma exceção não tratada no servidor.
Para obter mais informações, consulte Manipular erros em aplicativos ASP.NET CoreBlazor.
Compartilhamento de recursos entre origens (CORS)
A segurança do navegador geralmente restringe uma página da Web de fazer solicitações para uma origem diferente daquela que serviu a página da Web. Essa restrição é chamada de política de mesma origem. A política de mesma origem restringe (mas não impede) um site mal-intencionado de ler dados confidenciais de outro site. Para fazer solicitações do navegador para um ponto de extremidade com uma origem diferente, o ponto de extremidade deve habilitar o CORS (Cross-Origin Resource Sharing).
Para obter mais informações sobre CORS do lado do servidor, consulte Habilitar solicitações entre origens (CORS) no ASP.NET Core. Os exemplos do artigo não se referem diretamente a cenários de componentes Razor, mas o artigo é útil para aprender conceitos gerais de CORS.
Para obter informações sobre solicitações CORS do lado do cliente, consulte ASP.NET Core Blazor WebAssembly cenários de segurança adicionais.
Suporte antifalsificação
Para adicionar suporte antifalsificação a uma solicitação HTTP, injete o AntiforgeryStateProvider
e adicione um RequestToken
à coleção de cabeçalhos como um 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 obter mais informações, consulte Autenticação e autorização ASP.NET CoreBlazor.
Blazor exemplos de componentes da estrutura para testar o acesso à API da Web
Várias ferramentas de rede estão disponíveis publicamente para testar aplicativos de back-end da API da Web diretamente, como o Firefox Browser Developer. Blazor fonte de referência do framework inclui HttpClient recursos de teste que são úteis para testes:
HttpClientTest
ativos no dotnet/aspnetcore
repositório GitHub
Observação
Os links de documentação para a fonte de referência do .NET geralmente carregam a ramificação padrão do repositório, que representa o desenvolvimento atual para a próxima versão do .NET. Para selecionar uma tag para uma versão específica, use a lista suspensa Alternar entre ramificações ou tags. Para obter mais informações, consulte Como selecionar uma marca de versão do código-fonte ASP.NET Core (dotnet/AspNetCore.Docs #26205).
Recursos adicionais
Geral
- Compartilhamento de recursos entre origens (CORS) no W3C
- Habilitar solicitações entre origens (CORS) no ASP.NET Core: embora o conteúdo se aplique a aplicativos ASP.NET Core, não Razor a componentes, o artigo aborda conceitos gerais de CORS.
- Proteja os dados em Blazor Web Apps com renderização automática interativa
- Compartilhamento de recursos entre origens (CORS) no W3C
- Habilitar solicitações entre origens (CORS) no ASP.NET Core: embora o conteúdo se aplique a aplicativos ASP.NET Core, não Razor a componentes, o artigo aborda conceitos gerais de CORS.
Mitigação de ataques de excesso de postagem
As APIs da Web podem ser vulneráveis a um ataque de sobrepostagem , também conhecido como ataque de atribuição em massa . Um ataque de sobrepostagem ocorre quando um usuário mal-intencionado emite um formulário HTML POST para o servidor que processa dados para propriedades que não fazem parte do formulário renderizado e que o desenvolvedor não deseja permitir que os usuários modifiquem. O termo "overposting" significa literalmente que o utilizador malicioso efetuou um POST em excesso com o formulário.
Para obter orientações sobre como mitigar ataques de sobrepostagem, consulte Tutorial: Criar uma API da Web baseada em controlador com o ASP.NET Core.
Lado do servidor
ASP.NET Core cenários de segurança do lado do servidor e adicionais : Inclui cobertura sobre o uso de para fazer solicitações seguras para a API web. - Fazer solicitações HTTP usando IHttpClientFactory no ASP.NET Core
- Forçar HTTPS no ASP.NET Core
- Kestrel Configuração do ponto de extremidade HTTPS
Do lado do cliente
- ASP.NET Core Blazor WebAssembly cenários de segurança adicionais: Inclui cobertura sobre o uso de HttpClient para fazer solicitações de API da Web seguras.
- Usar a API do Graph com o ASP.NET Core Blazor WebAssembly
- Buscar API