Вызов веб-API из ASP.NET Core Blazor

Примечание.

Это не последняя версия этой статьи. В текущем выпуске см . версию .NET 8 этой статьи.

Внимание

Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.

В текущем выпуске см . версию .NET 8 этой статьи.

В этой статье описывается вызов веб-API из приложения Blazor.

Пакет

Пакет System.Net.Http.Json предоставляет методы расширения для System.Net.Http.HttpClient и System.Net.Http.HttpContent выполняет автоматическую сериализацию и десериализацию с помощью System.Text.Json. Пакет System.Net.Http.Json предоставляется общей платформой .NET и не требует добавления ссылки на пакет в приложение.

Примеры приложений

Ознакомьтесь с примерами dotnet/blazor-samples приложений в репозитории GitHub.

BlazorWebAppCallWebApi

Вызов внешнего (а не в Blazor веб-приложении) списка веб-API из Blazor веб-приложения:

  • Backend: веб-приложение API для поддержания списка дел на основе минимальных API. Веб-ПРИЛОЖЕНИЕ API — это отдельное приложение от Blazor веб-приложения, которое, возможно, размещено на другом сервере.
  • BlazorApp/BlazorApp.ClientBlazor: Веб-приложение, которое вызывает веб-приложение API с HttpClient операциями списка todo, такими как создание, чтение, обновление и удаление элементов (CRUD) из списка дел.

Для отрисовки на стороне клиента (CSR), которая включает в себя компоненты Интерактивного webAssembly и автокомпоненты, которые приняли CSR, вызовы выполняются с предварительно настроенной конфигурацией, зарегистрированной HttpClient в Program файле клиентского проекта (BlazorApp.Client):

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

Для отрисовки на стороне сервера (SSR), которая включает предварительно созданные и интерактивные компоненты сервера, предварительно созданные компоненты WebAssembly и автоматические компоненты, предварительно созданные или принятые SSR, вызовы выполняются с HttpClient зарегистрированным в Program файле проекта сервера (BlazorApp):

builder.Services.AddHttpClient();

Вызовите внутренний API списка фильмов (внутри Blazor веб-приложения), где API находится в серверном проекте Blazor веб-приложения:

  • BlazorAppBlazor: Веб-приложение, которое поддерживает список фильмов:
    • При выполнении операций в списке фильмов в приложении на сервере используются обычные вызовы API.
    • Когда вызовы API выполняются веб-клиентом, веб-API используется для операций списка фильмов на основе минимальных API.
  • BlazorApp.Client: клиентский проект Blazor веб-приложения, который содержит интерактивные компоненты WebAssembly и auto для управления пользователем списка фильмов.

Для CSR, включающего компоненты Interactive WebAssembly и автоматические компоненты, которые приняли CSR, вызовы API выполняются через клиентская служба (ClientMovieService), которая использует предварительно настроенный зарегистрированный HttpClient в Program файле клиентского проекта (BlazorApp.Client). Так как эти вызовы выполняются через общедоступный или частный веб-сайт, API списка фильмов — это веб-API.

В следующем примере показано, как получить список фильмов из конечной /movies точки:

public class ClientMovieService(HttpClient http) : IMovieService
{
    public async Task<Movie[]> GetMoviesAsync(bool watchedMovies)
    {
        return await http.GetFromJsonAsync<Movie[]>("movies") ?? [];
    }
}

Для SSR, включающего предварительно созданные и интерактивные компоненты сервера, предварительно созданные компоненты WebAssembly и автоматические компоненты, предварительно созданные или принятые SSR, вызовы выполняются непосредственно через серверную службу (ServerMovieService). API не зависит от сети, поэтому это стандартный API для операций CRUD списка фильмов.

В следующем примере показано, как получить список фильмов:

public class ServerMovieService(MovieContext db) : IMovieService
{
    public async Task<Movie[]> GetMoviesAsync(bool watchedMovies)
    {
        return watchedMovies ? 
            await db.Movies.Where(t => t.IsWatched).ToArrayAsync() : 
            await db.Movies.ToArrayAsync();
    }
}

BlazorWebAppCallWebApi_Weather

Пример приложения для данных о погоде, использующего потоковую отрисовку для данных о погоде.

BlazorWebAssemblyCallWebApi

Вызывает веб-API списка дел из Blazor WebAssembly приложения:

  • Backend: веб-приложение API для поддержания списка дел на основе минимальных API.
  • BlazorTodoBlazor WebAssembly: приложение, которое вызывает веб-API с предварительно настроенной HttpClient для операций CRUD списка дел.

Сценарии на стороне сервера для вызова внешних веб-API

Серверные компоненты вызывают внешние веб-API с помощью экземпляров, обычно созданных с помощью HttpClientIHttpClientFactory. Инструкции, применимые к приложениям на стороне сервера, см. в статье "Создание HTTP-запросов с помощью IHttpClientFactory" в ASP.NET Core.

Серверное приложение по умолчанию не включает HttpClient службу. Предоставьте HttpClient для приложения с помощью инфраструктуры фабрики HttpClient.

В файле Program:

builder.Services.AddHttpClient();

Следующий компонент Razor выполняет запрос к веб-API для получения ветвей GitHub, похожих на пример базового использования в статье Выполнения HTTP-запросов с помощью IHttpClientFactory в 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; }
    }
}

В предыдущем примере для C# 12 или более поздней версии для переменной создается пустой branches массив ([]). Для более ранних версий C#создайте пустой массив (Array.Empty<GitHubBranch>()).

Дополнительные рабочие примеры см. в примере отправки файлов на стороне сервера, который отправляет файлы в контроллер веб-API в статье о отправке файла ASP.NET CoreBlazor.

Абстракции служб для вызовов веб-API

Этот раздел относится к Blazor веб-приложения, которые поддерживают веб-API в проекте сервера или преобразуют вызовы веб-API во внешний веб-API.

При использовании интерактивных режимов webAssembly и автоматического отрисовки компоненты по умолчанию создаются предварительно. Автоматические компоненты также изначально отображаются на сервере в интерактивном режиме перед Blazor загрузкой пакета в клиент и активацией клиентской среды выполнения. Это означает, что компоненты, использующие эти режимы отрисовки, должны быть разработаны таким образом, чтобы они успешно выполнялись как от клиента, так и от сервера. Если компонент должен вызвать API на основе проекта сервера или преобразовать запрос во внешний веб-API (который находится за пределами Blazor веб-приложения) при выполнении на клиенте, рекомендуется абстрагировать этот вызов API за интерфейсом службы и реализовать версии клиента и сервера службы:

  • Версия клиента вызывает веб-API с предварительно настроенной HttpClientконфигурацией.
  • Версия сервера обычно может напрямую получить доступ к ресурсам на стороне сервера. HttpClient Внедрение на сервере, который выполняет обратные вызовы к серверу, не рекомендуется, так как сетевой запрос обычно не требуется. Кроме того, API может быть внешним для проекта сервера, но абстракция службы для сервера требуется для преобразования запроса каким-то образом, например для добавления маркера доступа к прокси-запросу.

При использовании режима отрисовки WebAssembly также можно отключить предварительную отрисовку, поэтому компоненты отображаются только от клиента. Дополнительные сведения см. в режимах отрисовки ASP.NET CoreBlazor.

Примеры (примеры приложений):

  • Веб-API списка фильмов в BlazorWebAppCallWebApi примере приложения.
  • Веб-API потоковой отрисовки данных о погоде BlazorWebAppCallWebApi_Weather в примере приложения.
  • Данные о погоде, возвращенные клиенту в BlazorWebAppOidc примерах приложений (не BFF) или BlazorWebAppOidcBff BFF. Эти приложения демонстрируют безопасные (веб-) вызовы API. Дополнительные сведения см. в статье "Защита ASP.NET Core Blazor Web App с помощью OpenID Подключение (OIDC)".

Blazor Внешние ВЕБ-API веб-приложения

Этот раздел применяется к Blazor веб-приложения, которые вызывают веб-API, поддерживаемые отдельным (внешним) проектом, возможно, размещенным на другом сервере.

Blazorвеб-приложения обычно предопределенные клиентские компоненты WebAssembly, а автоматические компоненты отображаются на сервере во время статической или интерактивной отрисовки на стороне сервера (SSR). HttpClient службы по умолчанию не регистрировались в Blazor основном проекте веб-приложения. Если приложение выполняется только HttpClient с службами, зарегистрированными в проекте, как описано в .Client разделе "Добавление HttpClient службы", выполнение приложения приводит к ошибке среды выполнения:

InvalidOperationException: не удается указать значение свойства "Http" в типе "... {COMPONENT}'. Зарегистрированная служба типа System.Net.Http.HttpClient отсутствует.

Используйте любой из следующих подходов:

  • HttpClient Добавьте службы в проект сервера, чтобы сделать доступным во HttpClient время SSR. Используйте следующую регистрацию службы в файле проекта Program сервера:

    builder.Services.AddHttpClient();
    

    Явная ссылка на пакет не требуется, так как HttpClient службы предоставляются общей платформой.

    Пример. Веб-API списка todo в BlazorWebAppCallWebApiпримере приложения

  • Если предварительная отрисовка не требуется для компонента WebAssembly, вызывающего веб-API, отключите предварительную отрисовку, следуя инструкциям в режимах отрисовки ASP.NET CoreBlazor. Если вы используете этот подход, вам не нужно добавлять HttpClient службы в основной проект Blazor веб-приложения, так как компонент не будет предварительно создан на сервере.

Дополнительные сведения см. в разделе "Не удается разрешить клиентские службы во время предварительной подготовки".

Предварительно созданные данные

При предварительной подготовке компоненты дважды отображаются: сначала статически, а затем интерактивно. Состояние не выполняет автоматический поток из предварительно созданного компонента в интерактивный. Если компонент выполняет асинхронные операции инициализации и отрисовывает разное содержимое для различных состояний во время инициализации, например "Загрузка..." Индикатор хода выполнения может отображаться при отрисовки компонента дважды.

Для этого можно выполнить поток предварительно созданного состояния с помощью API состояния сохраняемого компонента, который BlazorWebAppCallWebApi демонстрируется в примерах BlazorWebAppCallWebApi_Weatherприложений . Когда компонент отрисовывается в интерактивном режиме, он может отображаться так же, как с помощью того же состояния. Однако API в настоящее время не работает с расширенной навигацией, которую можно обойти, отключив расширенную навигацию по ссылкам на страницу (data-enhanced-nav=false). Дополнительные сведения см. на следующих ресурсах:

Добавление службы HttpClient

Рекомендации в этом разделе относятся к сценариям на стороне клиента.

Клиентские компоненты вызывают веб-API с помощью предварительно настроенной HttpClient службы, которая сосредоточена на выполнении запросов обратно на сервер источника. Дополнительные конфигурации службы HttpClient для других веб-API можно создать в коде разработчика. Запросы формируются с помощью вспомогательных приложений JSON Blazor или с помощью HttpRequestMessage. Запросы могут включать в себя конфигурацию параметра Fetch API.

Примеры конфигурации в этом разделе полезны только при вызове одного веб-API для одного HttpClient экземпляра в приложении. Когда приложение должно вызывать несколько веб-API, каждый из которых имеет собственный базовый адрес и конфигурацию, можно применить следующие подходы, описанные далее в этой статье:

  • Именованное с IHttpClientFactoryпомощьюHttpClient: каждый веб-API предоставляет уникальное имя. Если код приложения или Razor компонент вызывает веб-API, он использует именованный HttpClient экземпляр для вызова.
  • Типизированный HttpClient: каждый веб-API вводится. Если код приложения или Razor компонент вызывает веб-API, он использует типизированный HttpClient экземпляр для вызова.

Program В файле добавьте HttpClient службу, если она еще не присутствует из шаблона проекта, используемого Blazor для создания приложения:

builder.Services.AddScoped(sp => 
    new HttpClient
    {
        BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
    });

В предыдущем примере задается базовый адрес (IWebAssemblyHostEnvironment.BaseAddress), который получает базовый адрес builder.HostEnvironment.BaseAddress для приложения и обычно является производным от <base> значения тега href на хост-странице.

Наиболее распространенными вариантами использования для использования собственного базового адреса клиента являются:

  • Клиентский проект () Blazor веб-приложения (.Client.NET 8 или более поздней версии) выполняет вызовы веб-API из компонентов WebAssembly или кода, которые выполняются на клиенте в WebAssembly к API в серверном приложении.
  • Клиентский проект (Client) размещенного Blazor WebAssembly приложения вызывает веб-API к серверу (Server). Обратите внимание, что шаблон размещенного Blazor WebAssembly проекта больше недоступен в .NET 8 или более поздней версии. Однако размещенные Blazor WebAssembly приложения остаются поддерживаемыми для .NET 8.

Если вы вызываете внешний веб-API (не в том же пространстве URL-адресов, что и клиентское приложение), задайте универсальный код ресурса (URI) базовым адресом веб-API. Следующий пример задает базовый адрес веб-API, в котором выполняется отдельное веб-приложение API https://localhost:5001и готово к ответу на запросы из клиентского приложения:

builder.Services.AddScoped(sp => 
    new HttpClient
    {
        BaseAddress = new Uri("https://localhost:5001")
    });

JSВспомогательные службы ON

HttpClient доступен в качестве предварительно настроенной службы для отправки запросов обратно к серверу-источнику.

HttpClient и вспомогательные приложения JSON (System.Net.Http.Json.HttpClientJsonExtensions) также используются для вызова сторонних конечных точек веб-API. HttpClientреализуется с помощью API получения браузера и применяется к его ограничениям, включая применение политики одного источника, которая рассматривается далее в этой статье в разделе общего доступа к ресурсам (CORS).

Базовый адрес клиента устанавливается как адрес сервера-источника. Внедрите экземпляр HttpClient в компонент с помощью директивы @inject:

@using System.Net.Http
@inject HttpClient Http

Используйте пространство имен System.Net.Http.Json для доступа к HttpClientJsonExtensions, включая GetFromJsonAsync, PutAsJsonAsync и PostAsJsonAsync:

@using System.Net.Http.Json

В следующих разделах рассматриваются JSвспомогательные функции ON:

System.Net.Http включает дополнительные методы для отправки HTTP-запросов и получения HTTP-ответов, например для отправки запроса DELETE. Дополнительные сведения см. в разделе DELETE и дополнительные методы расширения.

GET из формата JSON (GetFromJsonAsync)

GetFromJsonAsync отправляет HTTP-запрос GET и анализирует текст ответа JSON для создания объекта.

В следующем коде компонента todoItems отображаются компонентом. GetFromJsonAsync вызывается после завершения инициализации компонента (OnInitializedAsync).

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

POST в формате JSON (PostAsJsonAsync)

PostAsJsonAsync отправляет по указанному универсальному коду ресурса (URI) запрос POST, в тексте которого содержится сериализованное значение в формате JSON.

В следующем коде компонента newItemName предоставляется связанным элементом компонента. Метод AddItem активируется путем выбора элемента <button>.

await Http.PostAsJsonAsync("todoitems", addItem);

PostAsJsonAsync возвращает HttpResponseMessage. Чтобы десериализовать содержимое JSON из ответного сообщения, используйте метод расширения ReadFromJsonAsync. В следующем примере данные о погоде ON считываются JSв виде массива:

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

PUT в формате JSON (PutAsJsonAsync)

PutAsJsonAsync отправляет HTTP-запрос PUT с содержимым в формате JSON.

В следующем коде компонента значения editItem для Name и IsCompleted предоставляются связанными элементами компонента. Элемент Id задается, когда элемент выбирается в другой части пользовательского интерфейса (не показан) и вызывается EditItem. Метод SaveItem активируется путем выбора элемента <button>. В следующем примере не отображается загрузка todoItems для краткости. Пример загрузки элементов см. в разделе GET из JSON (GetFromJsonAsync).

await Http.PutAsJsonAsync($"todoitems/{editItem.Id}", editItem);

PutAsJsonAsync возвращает HttpResponseMessage. Чтобы десериализовать содержимое JSON из ответного сообщения, используйте метод расширения ReadFromJsonAsync. В следующем примере данные о погоде ON считываются JSв виде массива:

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

PATCH as JSON (PatchAsJsonAsync)

PatchAsJsonAsync отправляет HTTP-запрос PATCH с содержимым в JSкодировке ON.

Примечание.

Дополнительные сведения см. в разделе JsonPatch в веб-API ASP.NET Core.

В следующем примере PatchAsJsonAsync получает JSдокумент ON PATCH в виде строки обычного текста с экранируемыми кавычками:

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

PatchAsJsonAsync возвращает HttpResponseMessage. Чтобы десериализовать содержимое JSON из ответного сообщения, используйте метод расширения ReadFromJsonAsync. В следующем примере данные элемента on todo считываются JSв виде массива. Пустой массив создается, если данные элемента не возвращаются методом, поэтому content не имеет значения NULL после выполнения инструкции:

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

Выложены с отступами, интервалами и незакрытыми кавычками, документ НЕкодированного PATCH отображается следующим JSобразом:

[
  {
    "operationType": 2,
    "path": "/IsComplete",
    "op": "replace",
    "value": true
  }
]

Чтобы упростить создание документов PATCH в приложении, выдавающем запросы PATCH, приложение может использовать поддержку .NET JSON PATCH, как показано в следующем руководстве.

Microsoft.AspNetCore.JsonPatch Установите пакет NuGet и используйте функции API пакета для создания JsonPatchDocument запроса PATCH.

Примечание.

Рекомендации по добавлению пакетов в приложения .NET см. в разделе Способы установки пакетов NuGet в статье Рабочий процесс использования пакета (документация по NuGet). Проверьте правильность версий пакета на сайте NuGet.org.

Добавьте @using директивы для System.Text.JsonSystem.Text.Json.Serializationпространств имен и Microsoft.AspNetCore.JsonPatch пространств имен в верхнюю часть Razor компонента:

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

Создайте JsonPatchDocument для TodoItem набора true набор для IsComplete использования Replace метода:

var patchDocument = new JsonPatchDocument<TodoItem>()
    .Replace(p => p.IsComplete, true);

Передайте операции документа (patchDocument.Operations) вызову PatchAsJsonAsync :

private async Task UpdateItem(long id)
{
    await Http.PatchAsJsonAsync(
        $"todoitems/{id}", 
        patchDocument.Operations, 
        new JsonSerializerOptions()
        {
            DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault
        });
}

JsonSerializerOptions.DefaultIgnoreCondition Значение имеет значение, указывающее, что JsonIgnoreCondition.WhenWritingDefault свойство игнорируется, только если оно равно значению по умолчанию для его типа.

Добавьте JsonSerializerOptions.WriteIndented параметр, true чтобы представить JSполезные данные ON в приятном формате для отображения. Запись отступа JSon не влияет на обработку запросов PATCH и обычно не выполняется в рабочих приложениях для запросов веб-API.

Следуйте указаниям в jsonPatch в статье ASP.NET Core web API , чтобы добавить действие контроллера PATCH в веб-API. Кроме того, обработка запросов PATCH может быть реализована как минимальный API с помощью следующих шагов.

Добавьте ссылку на пакет NuGet в Microsoft.AspNetCore.Mvc.NewtonsoftJson веб-приложение API.

Примечание.

Нет необходимости добавлять ссылку на пакет для Microsoft.AspNetCore.JsonPatch приложения, так как ссылка на Microsoft.AspNetCore.Mvc.NewtonsoftJson пакет автоматически добавляет ссылку Microsoft.AspNetCore.JsonPatchна пакет.

Program В файле добавьте директиву @using для Microsoft.AspNetCore.JsonPatch пространства имен:

using Microsoft.AspNetCore.JsonPatch;

Предоставьте конечную точку конвейеру обработки запросов веб-API:

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

Предупреждение

Как и в других примерах в JsonPatch в статье ASP.NET Core web API , предыдущий API PATCH не защищает веб-API от переопределения атак. Дополнительные сведения см. в руководстве по созданию веб-API с помощью ASP.NET Core.

Полный рабочий интерфейс PATCH см. в BlazorWebAppCallWebApiпримере приложения.

DELETE (DeleteAsync) и дополнительные методы расширения

System.Net.Http включает дополнительные методы расширения для отправки HTTP-запросов и получения HTTP-ответов. HttpClient.DeleteAsync используется для отправки запроса HTTP DELETE в веб-интерфейс API.

В следующем коде компонента элемент <button> вызывает метод DeleteItem. Связанный элемент <input> предоставляет id удаляемого элемента.

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

Именованный класс HttpClient с IHttpClientFactory

Поддерживаются службы IHttpClientFactory и конфигурация именованного класса HttpClient.

Примечание.

Вместо именованного класса HttpClient из IHttpClientFactory можно использовать типизированный класс HttpClient. Дополнительные сведения см. в разделе Типизированный HttpClient.

Добавьте в приложение пакет NuGet Microsoft.Extensions.Http.

Примечание.

Рекомендации по добавлению пакетов в приложения .NET см. в разделе Способы установки пакетов NuGet в статье Рабочий процесс использования пакета (документация по NuGet). Проверьте правильность версий пакета на сайте NuGet.org.

Program В файле клиентского проекта:

builder.Services.AddHttpClient("WebAPI", client => 
    client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress));

Если именованный клиент будет использоваться предварительно созданными клиентскими компонентами Blazor веб-приложения, предыдущая регистрация службы должна отображаться как в серверном проекте, так и .Client в проекте. На сервере builder.HostEnvironment.BaseAddress заменяется базовым адресом веб-API, описанным ниже.

Предыдущий пример на стороне клиента задает базовый адрес (builder.HostEnvironment.BaseAddressIWebAssemblyHostEnvironment.BaseAddress), который получает базовый адрес для клиентского приложения и обычно является производным от <base> значения тега href на хост-странице.

Наиболее распространенными вариантами использования для использования собственного базового адреса клиента являются:

  • Клиентский проект (.Client) Blazor веб-приложения, который вызывает веб-API из компонентов WebAssembly/Auto или кода, который выполняется на клиенте в WebAssembly к API в серверном приложении с тем же адресом узла.
  • Клиентский проект (Client) размещенного Blazor WebAssembly приложения, которое вызывает веб-API к серверу (Server).

Наиболее распространенным вариантом использования собственного базового адреса клиента является клиентский проект (Client) размещенного Blazor WebAssembly приложения, который вызывает веб-API к серверу (Server).

Если вы вызываете внешний веб-API (не в том же пространстве URL-адресов, что и клиентское приложение) или настраиваете службы в серверном приложении (например, для предварительного создания компонентов на сервере), задайте URI для базового адреса веб-API. Следующий пример задает базовый адрес веб-API, в котором выполняется отдельное веб-приложение API https://localhost:5001и готово к ответу на запросы из клиентского приложения:

builder.Services.AddHttpClient("WebAPI", client => 
    client.BaseAddress = new Uri(https://localhost:5001));

В следующем коде компонента:

  • Экземпляр IHttpClientFactory создает именованный объект HttpClient.
  • Имя HttpClient используется для выдачи запроса GET для JSданных прогноза погоды ON из веб-API по адресу /forecast.
@inject IHttpClientFactory ClientFactory

...

@code {
    private Forecast[]? forecasts;

    protected override async Task OnInitializedAsync()
    {
        var client = ClientFactory.CreateClient("WebAPI");

        forecasts = await client.GetFromJsonAsync<Forecast[]>("forecast") ?? [];
    }
}

Пример BlazorWebAppCallWebApiприложения демонстрирует вызов веб-API с именем HttpClient в его CallTodoWebApiCsrNamedClient компоненте. Дополнительные рабочие демонстрации в клиентском приложении на основе вызова Microsoft Graph с именем HttpClientсм. в разделе "Использование API Graph с ASP.NET Core Blazor WebAssembly".

Рабочая демонстрация в клиентском приложении на основе вызова Microsoft Graph с именем HttpClientсм. в статье "Использование API Graph с ASP.NET Core Blazor WebAssembly".

Типизированный HttpClient

Для возврата данных из одной или нескольких конечных точек веб-API типизированный класс HttpClient использует один или несколько экземпляров класса HttpClient приложения (заданных по умолчанию или именованных).

Примечание.

Вместо типизированного класса HttpClient можно использовать именованный класса HttpClient из IHttpClientFactory. Дополнительные сведения см. в разделе Именованный класс HttpClient с IHttpClientFactory.

Добавьте в приложение пакет NuGet Microsoft.Extensions.Http.

Примечание.

Рекомендации по добавлению пакетов в приложения .NET см. в разделе Способы установки пакетов NuGet в статье Рабочий процесс использования пакета (документация по NuGet). Проверьте правильность версий пакета на сайте NuGet.org.

В следующем примере возникает запрос GET для JSданных прогноза погоды ON из веб-API по адресу /forecast.

ForecastHttpClient.cs:

using System.Net.Http.Json;

namespace BlazorSample.Client;

public class ForecastHttpClient(HttpClient http)
{
    public async Task<Forecast[]> GetForecastAsync()
    {
        return await http.GetFromJsonAsync<Forecast[]>("forecast") ?? [];
    }
}

Program В файле клиентского проекта:

builder.Services.AddHttpClient<ForecastHttpClient>(client => 
    client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress));

Если типизированный клиент должен использоваться предварительно созданными клиентскими компонентами Blazor веб-приложения, то предыдущая регистрация службы должна отображаться как в серверном проекте, так и .Client в проекте. На сервере builder.HostEnvironment.BaseAddress заменяется базовым адресом веб-API, описанным ниже.

В предыдущем примере задается базовый адрес (IWebAssemblyHostEnvironment.BaseAddress), который получает базовый адрес builder.HostEnvironment.BaseAddress для клиентского приложения и обычно является производным от <base> значения тега href на хост-странице.

Наиболее распространенными вариантами использования для использования собственного базового адреса клиента являются:

  • Клиентский проект (.Client) Blazor веб-приложения, который вызывает веб-API из компонентов WebAssembly/Auto или кода, который выполняется на клиенте в WebAssembly к API в серверном приложении с тем же адресом узла.
  • Клиентский проект (Client) размещенного Blazor WebAssembly приложения, которое вызывает веб-API к серверу (Server).

Наиболее распространенным вариантом использования собственного базового адреса клиента является клиентский проект (Client) размещенного Blazor WebAssembly приложения, который вызывает веб-API к серверу (Server).

Если вы вызываете внешний веб-API (не в том же пространстве URL-адресов, что и клиентское приложение) или настраиваете службы в серверном приложении (например, для предварительного создания компонентов на сервере), задайте URI для базового адреса веб-API. Следующий пример задает базовый адрес веб-API, в котором выполняется отдельное веб-приложение API https://localhost:5001и готово к ответу на запросы из клиентского приложения:

builder.Services.AddHttpClient<ForecastHttpClient>(client => 
    client.BaseAddress = new Uri(https://localhost:5001));

Компоненты внедряют типизированный класс HttpClient для вызова веб-API.

В следующем коде компонента:

  • Внедряется экземпляр предыдущего класса ForecastHttpClient, который создает типизированный объект HttpClient.
  • Типизированный объект HttpClient позволяет создать запрос GET для получения из веб-API данных прогноза погоды в формате JSON.
@inject ForecastHttpClient Http

...

@code {
    private Forecast[]? forecasts;

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

Пример BlazorWebAppCallWebApiприложения демонстрирует вызов веб-API с типизированным HttpClient в его CallTodoWebApiCsrTypedClient компоненте. Обратите внимание, что компонент принимает и выполняет отрисовку на стороне клиента (CSR) (InteractiveWebAssemblyрежим отрисовки) с предварительной подготовкой, поэтому в файле типизированной регистрации клиентской службы отображается Program как серверный проект, так и .Client проект.

Руководство в этом разделе относится к сценариям на стороне клиента, которые используют проверку подлинности cookie.

Для cookieпроверки подлинности на основе, которая считается более безопасной, чем проверка подлинности маркера носителя, cookie учетные данные можно отправлять с каждым запросом веб-API путем вызова AddHttpMessageHandler с DelegatingHandler предварительно настроенным маркером HttpClient. Обработчик настраивает SetBrowserRequestCredentials с BrowserRequestCredentials.Includeпомощью , который советует браузеру отправлять учетные данные с каждым запросом, например заголовками проверки подлинности HTTP, в том числе cookieдля запросов между источниками.

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 в Program файле:

builder.Services.AddTransient<CookieHandler>();

Обработчик сообщений добавляется к любой предварительно настроенной HttpClient конфигурации, требующей cookie проверки подлинности:

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

Демонстрация см. в разделе Secure ASP.NET Core Blazor WebAssembly с ASP.NET Core Identity.

При создании HttpRequestMessageобъекта задайте учетные данные запроса браузера и заголовок напрямую:

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

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

HttpClient и HttpRequestMessage с параметрами запроса API Fetch

Руководство в этом разделе относится к сценариям на стороне клиента, которые используют проверку подлинности маркера носителя.

HttpClient (документация по API) и HttpRequestMessage можно использовать для настройки запросов. Например, можно указать метод HTTP и заголовки запроса. Следующий компонент выполняет запрос POST к конечной точке веб-API и отображает текст ответа.

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

BlazorРеализация на стороне клиента использует API получения и настраивает базовые параметры API получения для конкретного запроса с помощью HttpRequestMessage методов расширения и WebAssemblyHttpRequestMessageExtensions.HttpClient Задайте дополнительные параметры с помощью более универсального метода расширения SetBrowserRequestOption. Blazor и базовый API получения не добавляют или не изменяют заголовки запросов напрямую. Дополнительные сведения о том, как агенты пользователей, такие как браузеры, взаимодействуют с заголовками, см. в документации внешнего агента пользователя и других веб-ресурсах.

HTTP-ответ обычно помещается в буфер для выполнения операций синхронизации содержимого ответа. Для выполнения потоковой передачи ответов используйте метод расширения SetBrowserResponseStreamingEnabled для запроса.

Чтобы включить учетные данные в запрос независимо от источника, используйте метод расширения SetBrowserRequestCredentials.

requestMessage.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);

Дополнительные сведения о возможностях Fetch API см. на странице Веб-документация MDN. Параметры WindowOrWorkerGlobalScope.fetch().

Обработка ошибок

Обрабатывайте ошибки ответа веб-API в коде разработчика при их возникновении. Например, GetFromJsonAsync ожидает от веб-API ответ в формате JSON с заголовком Content-Type типа application/json. Если формат ответа отличается от JSON, при проверке содержимого создается исключение NotSupportedException.

В следующем примере показана неправильно написанная конечная точка URI для запроса данных прогноза погоды. URI должен иметь вид WeatherForecast, но отображается в вызове как WeatherForcast, в котором отсутствует буква e в Forecast.

Вызов GetFromJsonAsync ожидает ответ в формате JSON, но веб-API возвращает HTML с информацией о необработанном исключении, с заголовком Content-Type типа text/html. Необработанное исключение возникает из-за того, что путь к /WeatherForcast не найден, а ПО промежуточного слоя не может обслуживать страницу или представление для запроса.

Если выясняется, что содержимое ответа не является содержимым формата JSON, в методе OnInitializedAsync на клиенте возникает исключение NotSupportedException. Исключение перехватывается в блоке catch, где пользовательская логика может зарегистрировать ошибку или вывести понятное сообщение об ошибке для пользователя:

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

Примечание.

Предыдущий пример приведен только в качестве демонстрации. Веб-API можно настроить так, чтобы он возвращал ответ в формате JSON, даже если конечная точка не существует или на сервере возникает необработанное исключение.

Дополнительные сведения см. в статье Обработка ошибок в приложениях Blazor ASP.NET Core.

Общий доступ к ресурсам между источниками (CORS)

Безопасность в браузере запрещает запросы веб-страницы к другому домену, отличному от того, который обслуживает веб-страницу. Это ограничение называется политика одного источника. Эта политика запрещает (но не предотвращает) чтение вредоносным сайтом конфиденциальных данных с другого сайта. Чтобы отправлять запросы из браузера в конечную точку с другим источником, конечная точка должна включить общий доступ к ресурсам между источниками (CORS).

Дополнительные сведения о CORS на стороне сервера см. в разделе "Включение запросов между источниками" в ASP.NET Core. Примеры статьи не относятся непосредственно к Razor сценариям компонентов, но статья полезна для обучения общим понятиям CORS.

Сведения о запросах CORS на стороне клиента см. в ASP.NET дополнительных сценариях безопасности CoreBlazor WebAssembly.

Поддержка антифоргерии

Чтобы добавить поддержку антифоргерии в HTTP-запрос, введите AntiforgeryStateProvider и добавьте коллекцию RequestToken заголовков в виде 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);
    ...
}

Дополнительные сведения см. в разделе ASP.NET Проверка подлинности и авторизация CoreBlazor.

Примеры компонентов платформы Blazor для тестирования доступа к веб-API

Различные сетевые средства доступны для тестирования внутренних приложений веб-API напрямую, например Firefox Browser Developer. Источник ссылки на платформу Blazor содержит тестовые ресурсы HttpClient, которые полезны для тестирования.

Ресурсы HttpClientTest в репозитории GitHub dotnet/aspnetcore

Примечание.

По ссылкам в документации на справочные материалы по .NET обычно загружается ветвь репозитория по умолчанию, которая представляет текущую разработку для следующего выпуска .NET. Чтобы выбрать тег для определенного выпуска, используйте раскрывающийся список Switch branches or tags (Переключение ветвей или тегов). Дополнительные сведения см. в статье Выбор тега версии исходного кода ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Дополнительные ресурсы

Общие

на стороне сервера

На стороне клиента