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

Примечание.

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

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

Эта версия ASP.NET Core больше не поддерживается. Дополнительные сведения см. в статье о политике поддержки .NET и .NET Core. В текущем выпуске см . версию .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

Вызов внешнего (а не в) веб-API списка дел изBlazor Web AppBlazor Web App:

  • Backend: веб-приложение API для поддержания списка дел на основе минимальных API. Веб-ПРИЛОЖЕНИЕ API — это отдельное приложение, Blazor Web Appкоторое, возможно, размещено на другом сервере.
  • BlazorApp/BlazorApp.Client: вызывает Blazor Web App веб-приложение 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();

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

  • BlazorApp: содержит Blazor Web App список фильмов:
    • При выполнении операций в списке фильмов в приложении на сервере используются обычные вызовы API.
    • Когда вызовы API выполняются веб-клиентом, веб-API используется для операций списка фильмов на основе минимальных API.
  • BlazorApp.Client: клиентский проект, Blazor Web Appсодержащий интерактивные компоненты 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) => 
        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) => 
        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 с помощью экземпляров, обычно созданных с помощью HttpClient IHttpClientFactory. Инструкции, применимые к приложениям на стороне сервера, см. в статье "Создание 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 Web Apps, которые поддерживают веб-API в проекте сервера или преобразуют вызовы веб-API во внешний веб-API.

При использовании интерактивных режимов webAssembly и автоматического отрисовки компоненты по умолчанию создаются предварительно. Автоматические компоненты также изначально отображаются на сервере в интерактивном режиме перед Blazor загрузкой пакета в клиент и активацией клиентской среды выполнения. Это означает, что компоненты, использующие эти режимы отрисовки, должны быть разработаны таким образом, чтобы они успешно выполнялись как от клиента, так и от сервера. Если компонент должен вызвать API на основе проекта сервера или преобразовать запрос во внешний веб-API (который находится за пределами Blazor Web Appклиента), рекомендуется абстрагировать этот вызов 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 Connect (OIDC)".

Blazor Web App внешние веб-API

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

Blazor Web Appобычно предопределенные клиентские компоненты WebAssembly и автоматические компоненты отрисовки на сервере во время статической или интерактивной отрисовки на стороне сервера (SSR). HttpClient Службы по умолчанию не регистрировались в Blazor Web Appосновном проекте. Если приложение выполняется только 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 Web App , так как компонент не предопределен на сервере.

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

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

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

Для этого можно выполнить поток предварительно созданного состояния с помощью 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 на хост-странице.

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

  • Клиентский проект (.Client) (. Blazor Web App 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")
    });

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

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

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

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 отправляет запрос POST по указанному универсальному коду ресурса (URI), содержащий сериализованное значение в формате JSON в тексте запроса.

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

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

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

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. В следующем примере данные погоды JSON считываются в виде массива:

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

PATCH как JSON (PatchAsJsonAsync)

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

Примечание.

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

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

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

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

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

Выложены с отступами, интервалами и незакрытыми кавычками, документ НЕкодированного ИСПРАВЛЕНИЯ отображается в следующем формате JSON:

[
  {
    "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 чтобы представить полезные данные JSON в приятном формате для отображения. Запись отступа 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 Web App, предыдущая регистрация службы должна отображаться как в серверном проекте, так и .Client в проекте. На сервере builder.HostEnvironment.BaseAddress заменяется базовым адресом веб-API, описанным ниже.

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

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

  • Клиентский проект (.Client) Blazor Web App объекта, который вызывает веб-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 для данных прогноза погоды JSON из веб-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 для данных прогноза погоды JSON из веб-API /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") ?? [];
}

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

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

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

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

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

  • Клиентский проект (.Client) Blazor Web App объекта, который вызывает веб-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помощью , который советует браузеру отправлять учетные данные с каждым запросом, например заголовками cookie или HTTP-аутентификации, включая запросы между источниками.

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 ожидает ответа JSON от веб-API с заголовком 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).

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

Общие

Устранение перепоставок атак

Веб-API могут быть уязвимы к атаке с перепоступом , также известной как атака массового назначения . Атака переступа возникает, когда злоумышленник выдает HTML-форму POST на сервер, который обрабатывает данные для свойств, не входящих в отрисованную форму, и что разработчик не хочет изменять пользователей. Термин "overposting" буквально означает, что вредоносный пользователь переназначил posTed с формой.

Рекомендации по устранению атак на перепоступление см. в руководстве по созданию веб-API с помощью ASP.NET Core.

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

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