Chamar uma API Web de ASP.NET Core Blazor

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.

Aviso

Esta versão do ASP.NET Core não tem mais suporte. Para obter mais informações, confira .NET e a Política de Suporte do .NET Core. Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.

Importante

Essas informações relacionam-se ao produto de pré-lançamento, que poderá ser substancialmente modificado antes do lançamento comercial. A Microsoft não oferece nenhuma garantia, explícita ou implícita, quanto à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 Web de um aplicativo Blazor.

Pacote

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.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.

Aplicativos de exemplo

Consulte os aplicativos de amostra no repositório GitHub dotnet/blazor-samples.

BlazorWebAppCallWebApi

Chame uma API Web de lista externa de tarefas pendentes (não no Blazor Web App) de um Blazor Web App:

  • Backend: um aplicativo de API Web para manter uma lista de tarefas pendentes, com base APIs mínimas. O aplicativo de API Web é um aplicativo separado do Blazor Web App, possivelmente hospedado em um servidor diferente.
  • BlazorApp/BlazorApp.Client: um Blazor Web App que chama o aplicativo de API Web com um HttpClient para operações de lista de tarefas pendentes, como criar, ler, atualizar e excluir itens (CRUD) da lista de tarefas pendentes.

Para a CSR (renderização do lado do cliente), que inclui componentes WebAssembly interativos e componentes automáticos que adotaram a CSR, as chamadas são feitas com um HttpClient pré-configurado registrado no arquivo Program do projeto cliente (BlazorApp.Client):

builder.Services.AddScoped(sp =>
    new HttpClient
    {
        BaseAddress = new Uri(builder.Configuration["FrontendUrl"] ?? "https://localhost:5002")
    });

Para SSR (renderização do lado do servidor), que inclui componentes do Servidor pré-gerados e interativos, componentes WebAssembly pré-gerados e componentes automáticos que são pré-gerados ou adotaram o SSR, as chamadas são feitas com um HttpClient registrado no arquivo Program do projeto do servidor (BlazorApp):

builder.Services.AddHttpClient();

Chame uma API de lista de filmes interna (dentro do Blazor Web App), em que a API reside no projeto do 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 à API comuns são usadas.
    • Quando as chamadas à API são feitas por um cliente baseado na Web, uma API 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 WebAssembly interativos e Auto para gerenciamento de usuário da lista de filmes.

Para CSR, que inclui componentes interativos do WebAssembly e componentes automáticos que adotaram o CSR, as chamadas à 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 da lista de filmes é uma API Web.

O exemplo a seguir obtém uma lista de filmes do ponto de extremidade /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 pré-gerados e interativos, componentes WebAssembly pré-gerados e componentes automáticos que são pré-gerados ou adotaram o 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 da 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();
}

BlazorWebAppCallWebApi_Weather

Um aplicativo de amostra de dados meteorológicos que usa a renderização de streaming para dados meteorológicos.

BlazorWebAssemblyCallWebApi

Chama uma API Web de lista completa de um aplicativo Blazor WebAssembly:

  • Backend: um aplicativo de API Web para manter uma lista de tarefas pendentes, com base APIs mínimas.
  • BlazorTodo: um aplicativo Blazor WebAssembly que chama a API Web com uma HttpClient pré-configurada para operações CRUD de lista de tarefas pendentes.

Cenários do lado do servidor para chamar APIs Web externas

Os componentes baseados em servidor chamam às APIs Web externas utilizando instâncias HttpClient, normalmente criadas usando IHttpClientFactory. Para obter diretrizes que se aplicam a aplicativos do lado do servidor, consulte Fazer solicitações HTTP usando o IHttpClientFactory no ASP.NET Core.

Um aplicativo no lado do servidor não inclui um serviço HttpClient. Forneça um HttpClient ao aplicativo usando a HttpClient infraestrutura de fábrica.

No arquivo Program:

builder.Services.AddHttpClient();

O componente Razor a seguir faz uma solicitação para uma API Web para branches do GitHub semelhante ao exemplo deUso 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 Blazor Server 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()
    {
        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();

        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#, crie uma matriz vazia (Array.Empty<GitHubBranch>()).

Para obter um exemplo de trabalho adicional, confira o exemplo de upload de arquivo do lado do servidor que carrega arquivos em um controlador de API Web no artigo sobre uploads de arquivo Blazor do ASP.NET Core.

Abstrações de serviço para chamadas à API Web

Esta seção se aplica a Blazor Web Apps que mantêm uma API Web no projeto do servidor ou transformam chamadas à API Web para uma API Web externa.

Ao usar os modos interativos WebAssembly e Renderização automática, os componentes são pré-gerados por padrão. Os componentes automáticos também são inicialmente renderizados interativamente do servidor antes que o pacote Blazor seja baixado para o cliente, e o runtime do lado do cliente seja ativado. Isso significa que os componentes que usam esses modos de renderização devem ser projetados para que sejam executados com êxito no cliente e no servidor. Se o componente precisar chamar uma API baseada em projeto de servidor ou transformar uma solicitação para uma API Web externa (que está fora do Blazor Web App) ao ser executada no cliente, a abordagem recomendada é abstrair essa chamada à API por trás de uma interface de serviço e implementar as versões de cliente e servidor do serviço:

  • A versão do cliente chama a API Web com um HttpClient pré-configurado.
  • A versão do servidor normalmente pode acessar os recursos do lado do servidor diretamente. Injetar um HttpClient no servidor que faz chamadas de volta para o servidor não é recomendado, 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 proxie.

Ao usar o modo de renderização WebAssembly, você também tem a opção de desabilitar a pré-geração, de modo que os componentes só são renderizados do cliente. Para obter mais informações, consulte ASP.NET Core Blazor modos de renderização.

Exemplos (aplicativos de exemplo):

  • API Web da lista de filmes no aplicativo de amostra BlazorWebAppCallWebApi.
  • Streaming renderizando a API Web de dados meteorológicos no aplicativo de amostra BlazorWebAppCallWebApi_Weather.
  • Dados meteorológicos retornados ao cliente nos aplicativos de exemplo BlazorWebAppOidc (padrão não BFF) ou BlazorWebAppOidcBff (padrão BFF). Esses aplicativos demonstram chamadas à API segura (Web). Para mais informações, consulte Proteger um Blazor Web App do ASP.NET Core com o OIDC (OpenID Connect).

APIs Web externas do Blazor Web App

Esta seção se aplica a Blazor Web Apps que chamam uma API Web mantida por um projeto separado (externo), possivelmente hospedado em um servidor diferente.

Normalmente, os Blazor Web Apps pré-renderizam componentes WebAssembly do lado do cliente, e os componentes Auto são renderizados no servidor durante a renderização estática ou interativa do lado do servidor (SSR). Os serviços HttpClient não são registrados por padrão no projeto principal de um Blazor Web App. Se o aplicativo for executado apenas com os serviços HttpClient registrados no projeto .Client, conforme descrito na seção Adicionar o serviço HttpClient, a execução do aplicativo resultará em um erro de runtime:

InvalidOperationException: não é possível fornecer um valor para a propriedade “Http” no tipo '”.. {COMPONENT}”. Não há nenhum serviço registrado do tipo 'System.Net.Http.HttpClient'.

Use qualquer uma das seguintes abordagens:

  • Adicione os serviços HttpClient ao projeto do servidor para tornar o HttpClient disponível durante a SSR. Use o seguinte registro de serviço no arquivo Program do projeto do servidor:

    builder.Services.AddHttpClient();
    

    Os serviços HttpClient são fornecidos pela estrutura compartilhada, portanto, uma referência de pacote no arquivo de projeto do aplicativo não é necessária.

    Exemplo: API Web da lista de tarefas no BlazorWebAppCallWebApi aplicativo de exemplo

  • Se a pré-renderização não for necessária para o componente WebAssembly que chama a API Web, desabilite-a seguindo as diretrizes em modos de renderização do ASP.NET Core Blazor. Se você adotar essa abordagem, não precisará adicionar serviços HttpClient ao projeto principal do Blazor Web App, porque o componente não será pré-renderizado no servidor.

Para obter mais informações, confira Serviços do lado do cliente não resolvidos durante a pré-renderização.

Dados pré-renderizados

Ao pré-renderizar, os componentes são renderizados duas vezes: primeiro estaticamente e, em seguida, 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 diferentes estados durante a inicialização, como um indicador de progresso de “Carregando...”, você poderá ver uma oscilação quando o componente for renderizado duas vezes.

Você pode resolver isso fluindo o estado pré-renderizado usando a API Persistent Component State, que os aplicativos de amostra BlazorWebAppCallWebApi e BlazorWebAppCallWebApi_Weather demonstram. Quando o componente é renderizado interativamente, ele pode renderizar da mesma maneira usando o mesmo estado. No entanto, atualmente, a API não funciona com navegação aprimorada, o que pode ser feito desabilitando a navegação aprimorada em links para a página (data-enhanced-nav=false). Para saber mais, consulte os recursos a seguir:

Adicionar o serviço HttpClient

As diretrizes nesta seção se aplicam a cenários do lado do cliente.

Os componentes do lado do cliente chamam à API Web utilizando um serviço HttpClient pré-configurado, que se concentra em fazer solicitações de volta ao servidor de origem. Configurações de serviço adicionais HttpClient para outras APIs Web podem ser criadas no código do desenvolvedor. As solicitações são compostas usando auxiliares JSON Blazor ou com HttpRequestMessage. As solicitações podem incluir a configuração de opção Buscar API.

Os exemplos de configuração nesta seção são úteis apenas quando uma única API Web é chamada para uma única instância HttpClient no aplicativo. Quando o aplicativo precisar chamar várias APIs Web, cada uma com seu próprio endereço base e configuração, você poderá adotar as seguintes abordagens, que serão tratadas mais adiante neste artigo:

  • Nomeado HttpClient com IHttpClientFactory: cada API Web recebe um nome exclusivo. Quando o código do aplicativo ou um componente Razor chama uma API Web, ele usa uma instância HttpClient nomeada para fazer a chamada.
  • Tipada HttpClient: cada API Web é tipada. Quando o código do aplicativo ou um Razorcomponente chama uma API da web, ele usa uma instância tipada HttpClient para fazer a chamada.

No arquivo Program, adicione um serviço HttpClient se ele ainda não estiver presente em um modelo de projeto Blazor utilizado 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 do aplicativo e é normalmente derivado do valor href da tag <base> 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 (.NET 8 ou posterior) faz chamadas à API Web a partir de componentes WebAssembly ou código executado no cliente em WebAssembly a APIs no aplicativo do servidor.
  • O projeto cliente (Client) de um aplicativo hospedado Blazor WebAssembly faz chamadas à API Web para o projeto do servidor (Server). Observe que o modelo de projeto Blazor WebAssembly hospedado não está mais disponível no .NET 8 ou posterior. No entanto, os aplicativos hospedados Blazor WebAssembly permanecem com suporte pelo .NET 8.

Se estiver chamando uma API Web externa (que não esteja no mesmo espaço de URL que o aplicativo cliente), defina o URI como o endereço base da API Web. O exemplo a seguir define o endereço base da API Web como https://localhost:5001, no qual um aplicativo de API 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")
    });

Auxiliares JSON

HttpClient está disponível como um serviço pré-configurado para fazer solicitações de volta ao servidor de origem.

Os auxiliares HttpClient e JSON (System.Net.Http.Json.HttpClientJsonExtensions) também são usados para chamar pontos de extremidade da API Web de terceiros. HttpClient é implementado usando a API de busca do navegador e está sujeito a suas limitações, incluindo a imposição da política de mesma origem, que é discutida posteriormente neste artigo na seção Compartilhamento de Recursos entre Origens (CORS).

O endereço base do cliente é definido como o endereço do servidor de origem. Insere 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, PutAsJsonAsync e PostAsJsonAsync:

@using System.Net.Http.Json

As seções a seguir abrangem os auxiliares JSON:

System.Net.Http inclui métodos de extensão adicionais para enviar solicitações HTTP e receber respostas HTTP. Para obter mais informações, consulte a seção DELETE e métodos de extensão adicionais seção.

GET 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 é concluído inicializando (OnInitializedAsync).

todoItems = await Http.GetFromJsonAsync<TodoItem[]>("todoitems");

POST como JSON (PostAsJsonAsync)

PostAsJsonAsync envia uma solicitação POST ao URI especificado que contém o valor serializado como JSON no corpo da solicitação.

No código do componente a seguir, newItemName é fornecido por um elemento associado do componente. O método AddItem é disparado selecionando 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 código do componente a seguir, os valores editItem para Name e IsCompleted são fornecidos por elementos associados do componente. O Id do item é definido quando o item é selecionado em outra parte da interface do usuário (não mostrado) e EditItem é chamado. O método SaveItem é disparado selecionando o elemento <button>. O exemplo a seguir não mostra o carregamento de todoItems para fins de brevidade. Consulte a seção GET de JSON (GetFromJsonAsync) para ver um exemplo de itens de carregamento.

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, confira JsonPatch em APIs Web do ASP.NET Core.

No exemplo a seguir, PatchAsJsonAsync recebe um documento JSON PATCH como uma cadeia de caracteres de texto sem formatação com aspas de escape:

await Http.PatchAsJsonAsync(
    $"todoitems/{id}", 
    "[{\"operationType\":2,\"path\":\"/IsComplete\",\"op\":\"replace\",\"value\":true}]");

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ê dados de item de tarefas pendentes JSON como uma matriz. Uma matriz vazia será criada se nenhum dado de item for retornado pelo método, portanto content não será nulo após a execução da instrução:

var response = await Http.PatchAsJsonAsync(...);
var content = await response.Content.ReadFromJsonAsync<TodoItem[]>() ??
    Array.Empty<TodoItem>();

Disposto com recuo, espaçamento 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 ao PATCH JSON do .NET, como demonstram as diretrizes a seguir.

Instale o pacote NuGet Microsoft.AspNetCore.JsonPatch e use os recursos da API do pacote para compor um JsonPatchDocument para uma solicitação PATCH.

Observação

Para obter diretrizes sobre como adicionar pacotes a aplicativos .NET, consulte os artigos em Instalar e gerenciar pacotes no Fluxo de trabalho de consumo de pacotes (documentação do NuGet). Confirme as versões corretas de pacote em NuGet.org.

Adicione diretivas @using para os namespaces System.Text.Json, System.Text.Json.Serialization e Microsoft.AspNetCore.JsonPatch à parte superior do componente Razor:

@using System.Text.Json
@using System.Text.Json.Serialization
@using Microsoft.AspNetCore.JsonPatch

Redija o JsonPatchDocument para 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 como JsonIgnoreCondition.WhenWritingDefault para ignorar uma propriedade somente se ela for igual ao valor padrão de seu tipo.

Adicione JsonSerializerOptions.WriteIndented definido como true se quiser apresentar o conteúdo JSON em um formato interessante para exibição. Escrever JSON recuado não tem nenhuma influência no processamento de solicitações PATCH e geralmente não é executado em aplicativos de produção para solicitações de API Web.

Siga as diretrizes no artigo JsonPatch na API Web do ASP.NET Core para adicionar uma ação do controlador PATCH à API 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.Mvc.NewtonsoftJson ao aplicativo da API Web.

Observação

Não é necessário 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 ponto de extremidade para o pipeline de processamento de solicitação 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();
});

Aviso

Assim como acontece com os outros exemplos no artigo JsonPatch na API Web do ASP.NET Core, a API PATCH anterior não protege a API Web contra ataques de postagem excessiva. Para obter mais informações, consulte Tutorial: criar uma API Web com o ASP.NET Core.

Para uma experiência PATCH totalmente funcional, consulte o BlazorWebAppCallWebApi aplicativo de exemplo.

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 Web.

No código do componente a seguir, o <button> elemento chama o método DeleteItem. O elemento associado <input> fornece o item id a ser excluído.

await Http.DeleteAsync($"todoitems/{id}");

HttpClient nomeado com IHttpClientFactory

IHttpClientFactory há suporte para os serviços e a configuração de um HttpClient nomeado.

Observação

Uma alternativa ao uso de um HttpClient nomeado de um IHttpClientFactory é usar um HttpClient digitado. Para obter mais informações, veja a seção HttpClient tipado.

Adicione o Pacote NuGet Microsoft.Extensions.Http ao aplicativo.

Observação

Para obter diretrizes sobre como adicionar pacotes a aplicativos .NET, consulte os artigos em Instalar e gerenciar pacotes no Fluxo de trabalho de consumo de pacotes (documentação do NuGet). Confirme as versões corretas de 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 deve ser usado por componentes pré-renderizados do lado do cliente de Blazor Web App, o registro de serviço anterior aparecerá no projeto do servidor e no projeto .Client. No servidor, builder.HostEnvironment.BaseAddress é substituído pelo endereço base da API Web, que é descrito mais abaixo.

O exemplo do lado do cliente anterior define o endereço base com builder.HostEnvironment.BaseAddress (IWebAssemblyHostEnvironment.BaseAddress), que obtém o endereço base do aplicativo do lado do cliente e é normalmente derivado do valor href da tag <base> 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 à API Web a partir de componentes WebAssembly/Automáticos ou de código executado no cliente em WebAssembly para APIs no aplicativo do servidor no mesmo endereço de host.
  • O projeto cliente (Client) de um aplicativo hospedado Blazor WebAssembly que faz chamadas à API Web para o projeto do servidor (Server).

O caso de uso mais comum para usar o próprio endereço base do cliente está no projeto do cliente (Client) de um aplicativo Blazor WebAssembly hospedado que faz chamadas à API Web para o projeto do servidor (Server).

Se você estiver chamando uma API 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 Web. O exemplo a seguir define o endereço base da API Web como https://localhost:5001, no qual um aplicativo de API 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 do componente:

  • Uma instância de IHttpClientFactory cria um nome HttpClient.
  • O HttpClient nomeado é usado para emitir uma solicitação GET para os dados de previsão do tempo JSON na 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 BlazorWebAppCallWebApi aplicativo de exemplo demonstra a chamada de uma API da Web com um HttpClient nomeado em seu componente CallTodoWebApiCsrNamedClient. Para obter uma demonstração funcional adicional em um aplicativo cliente baseado na chamada do Microsoft Graph com um HttpClient nomeado, confira Usar a API do Graph com o ASP.NET Core Blazor WebAssembly.

Para obter uma demonstração funcional em um aplicativo cliente baseado na chamada do Microsoft Graph com um HttpClient nomeado, confira Usar a API do Graph com o ASP.NET Core Blazor WebAssembly.

HttpClient tipado

O HttpClient tipado usa uma ou mais instâncias do aplicativo HttpClient, padrão ou nomeado, para retornar dados de um ou mais pontos de extremidade da API Web.

Observação

Uma alternativa ao uso de um HttpClient tipado é usar um HttpClient nomeado de um IHttpClientFactory. Para obter mais informações, confira a seçãoHttpClient nomeado com IHttpClientFactory.

Adicione o Pacote NuGet Microsoft.Extensions.Http ao aplicativo.

Observação

Para obter diretrizes sobre como adicionar pacotes a aplicativos .NET, consulte os artigos em Instalar e gerenciar pacotes no Fluxo de trabalho de consumo de pacotes (documentação do NuGet). Confirme as versões corretas de pacote em NuGet.org.

O exemplo a seguir emite uma solicitação GET para dados de previsão do tempo JSON na API Web 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 digitado deve ser usado por componentes pré-renderizados do lado do cliente de um Blazor Web App, o registro de serviço anterior aparecerá no projeto do servidor e no projeto .Client. No servidor, builder.HostEnvironment.BaseAddress é substituído pelo endereço base da API 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 do aplicativo do lado do cliente e é normalmente derivado do valor href da tag <base> 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 à API Web a partir de componentes WebAssembly/Automáticos ou de código executado no cliente em WebAssembly para APIs no aplicativo do servidor no mesmo endereço de host.
  • O projeto cliente (Client) de um aplicativo hospedado Blazor WebAssembly que faz chamadas à API Web para o projeto do servidor (Server).

O caso de uso mais comum para usar o próprio endereço base do cliente está no projeto do cliente (Client) de um aplicativo Blazor WebAssembly hospedado que faz chamadas à API Web para o projeto do servidor (Server).

Se você estiver chamando uma API 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 Web. O exemplo a seguir define o endereço base da API Web como https://localhost:5001, no qual um aplicativo de API 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 HttpClient tipado para chamar a API Web.

No seguinte código do componente:

  • Uma instância da ForecastHttpClient anterior é injetada, o que cria um HttpClient tipado.
  • O HttpClient digitado é usado para emitir uma solicitação GET para dados de previsão do tempo JSON na API Web.
@inject ForecastHttpClient Http

...

@code {
    private Forecast[]? forecasts;

    protected override async Task OnInitializedAsync()
    {
        forecasts = await Http.GetForecastAsync();
    }
}

O BlazorWebAppCallWebApiaplicativo de exemplo demonstra a chamada de uma API Web com um HttpClient digitado em seu componente CallTodoWebApiCsrTypedClient. Observe que o componente adota a renderização do lado do cliente (CSR) (InteractiveWebAssemblymodo de renderização) com pré-renderização, portanto o registro do serviço do cliente digitado aparece no arquivo Program do projeto do servidor e do projeto .Client.

As diretrizes nesta seção se aplicam a cenários do lado do cliente que dependem de uma autenticação cookie.

Para 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 em um 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 entre origens.

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

CookieHandler é registrado no arquivo Program:

builder.Services.AddTransient<CookieHandler>();

O manipulador de mensagens é adicionado a qualquer HttpClient pré-configurado que exija autenticação cookie:

builder.Services.AddHttpClient(...)
    .AddHttpMessageHandler<CookieHandler>();

Ao compor um HttpRequestMessage, defina as credenciais de solicitação do navegador e o cabeçalho diretamente:

var requestMessage = new HttpRequestMessage() { ... };

requestMessage.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);
requestMessage.Headers.Add("X-Requested-With", ["XMLHttpRequest"]);

HttpClient e HttpRequestMessage com opções de solicitação de API Fetch

As diretrizes nesta seção se aplicam a cenários do lado do cliente que dependem da autenticação de token de portador.

HttpClient (Documentaçãoda API) e HttpRequestMessage pode ser usado para personalizar solicitações. Por exemplo, você pode especificar o método HTTP e os cabeçalhos de solicitação. O componente a seguir faz uma solicitação POST para um ponto de extremidade 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()
    {
        var requestMessage = 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))
        {
            requestMessage.Headers.Authorization =
                new AuthenticationHeaderValue("Bearer", token.Value);

            requestMessage.Content.Headers.TryAddWithoutValidation(
                "x-custom-header", "value");

            var response = await Http.SendAsync(requestMessage);
            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; }
    }
}

A implementação do lado do cliente de Blazor por parte do HttpClient usa a API de Fetch e configura as opções subjacentes da API de Fetch específicas da solicitação por meio dos métodos de extensão HttpRequestMessage e de WebAssemblyHttpRequestMessageExtensions. Defina opções adicionais usando o método de extensão genérico SetBrowserRequestOption. O Blazor e a API de Fetch subjacente não adiciona nem modifica diretamente os cabeçalhos de solicitação. Para obter mais informações sobre como os agentes de usuário, como navegadores, interagem com os cabeçalhos, consulte os conjuntos de documentação de agentes de usuário externos e outros recursos da Web.

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 resposta, use o método de extensão SetBrowserResponseStreamingEnabled na solicitação.

Para incluir credenciais em uma solicitação entre origens, use o método de extensão SetBrowserRequestCredentials:

requestMessage.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);

Para obter mais informações sobre as opções da API fetch, consulte Documentos da Web MDN: WindowOrWorkerGlobalScope.fetch(): Parâmetros.

Tratar erros

Manipule erros de resposta da API Web no código do desenvolvedor quando eles 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 gerará um NotSupportedException.

No exemplo a seguir, o ponto de extremidade do URI para a solicitação de dados de previsão do tempo está escrito incorretamente. O URI deve ser para WeatherForecast, mas aparece na chamada como WeatherForcast, o que está faltando na letra e em Forecast.

A chamada GetFromJsonAsync espera que JSON seja retornado, mas a API Web retorna HTML para uma exceção sem tratamento com um Content-Type de text/html. A exceção sem tratamento ocorre porque o caminho para /WeatherForcast não foi encontrado e o middleware não pode servir a uma página ou exibição para a solicitação.

No OnInitializedAsync cliente, NotSupportedException é gerado quando o conteúdo da resposta é validado como não JSON. A exceção é capturada no bloco, em que a lógica catch 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 &#8451;
                @forecast.TemperatureF &#8457;
            </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 tem fins de demonstração. Uma API Web pode ser configurada para retornar JSON mesmo quando um ponto de extremidade não existir ou ocorrer uma exceção sem tratamento no servidor.

Para obter mais informações, confira Manipular erros nos aplicativos Blazor do ASP.NET Core.

Compartilhamento de Recursos entre Origens (CORS)

A segurança do navegador restringe uma página da Web de fazer solicitações para um domínio diferente daquele 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) que um site mal-intencionado leia 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 Compartilhamento de Recursos entre Origens (CORS).

Para obter mais informações sobre o CORS do lado do servidor, consulte Habilitar o CORS (Solicitações entre Origens) 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 à anti-falsificação

Para adicionar suporte à anti-falsificaçã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();
    var request = new HttpRequestMessage(HttpMethod.Post, "action");
    request.Headers.Add("RequestVerificationToken", antiforgery.RequestToken);
    var response = await client.SendAsync(request);
    ...
}

Para obter mais informações, confira Autenticação e autorização Blazor do ASP.NET Core.

Exemplos de componente da estrutura Blazor para testar o acesso à API Web

Várias ferramentas de rede estão disponíveis publicamente para testar aplicativos de back-end da API Web diretamente, como o Desenvolvedor do Firefox Browser. Blazor A origem de referência da estrutura inclui ativos de teste HttpClient que são úteis para teste:

Ativos HttpClientTest no dotnet/aspnetcore repositório GitHub

Observação

Os links de documentação para a fonte de referência do .NET geralmente carregam o branch padrão do repositório, que representa o desenvolvimento atual da próxima versão do .NET. Para selecionar uma marca para uma versão específica, use a lista suspensa para Alternar branches ou marcas. Para saber mais, confira Como selecionar uma marca de versão do código-fonte do ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Recursos adicionais

Geral

Mitigação de ataques de excesso de postagem

As APIs Web podem ser vulneráveis a um ataque de excesso de postagem, também conhecido como ataque de atribuição em massa. Um ataque de excesso de postagem ocorre quando um usuário mal-intencionado emite um POST de formulário HTML 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 “excesso de postagem” literalmente significa que o usuário mal-intencionado ultrapassou o limite de POSTs com o formulário.

Para obter diretrizes sobre como mitigar ataques de excesso de postagem, consulte Tutorial: Criar uma API Web com ASP.NET Core.

Lado do servidor

Lado do cliente