Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Note
Это не последняя версия этой статьи. Текущий выпуск можно найти в версии этой статьи о .NET 10.
Warning
Эта версия ASP.NET Core больше не поддерживается. Для получения дополнительной информации см. Политику поддержки .NET и .NET Core. Текущий выпуск можно найти в версии этой статьи о .NET 10.
В этой статье описывается вызов веб-API из приложения Blazor.
Сценарии на стороне сервера для вызова внешних веб-API
Серверные компоненты вызывают внешние веб-API с помощью экземпляров HttpClient, обычно созданных с помощью IHttpClientFactory. Инструкции, применимые к серверным приложениям, см. в разделе HTTP-запросы с помощью IHttpClientFactory — ASP.NET Core.
Серверное приложение не включает службу HttpClient. Предоставьте HttpClient для приложения с помощью фабричной инфраструктуры HttpClient.
В файле Program:
builder.Services.AddHttpClient();
Следующий компонент Razor выполняет запрос к веб-API для веток GitHub, аналогичный примеру Basic Usage из статьи 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 server-side Razor component</h1>
@if (getBranchesError || branches is null)
{
<p>Unable to get branches from GitHub. Please try again later.</p>
}
else
{
<ul>
@foreach (var branch in branches)
{
<li>@branch.Name</li>
}
</ul>
}
@code {
private IEnumerable<GitHubBranch>? branches = [];
private bool getBranchesError;
private bool shouldRender;
protected override bool ShouldRender() => shouldRender;
protected override async Task OnInitializedAsync()
{
using var request = new HttpRequestMessage(HttpMethod.Get,
"https://api.github.com/repos/dotnet/AspNetCore.Docs/branches");
request.Headers.Add("Accept", "application/vnd.github.v3+json");
request.Headers.Add("User-Agent", "HttpClientFactory-Sample");
var client = ClientFactory.CreateClient();
using var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
using var responseStream = await response.Content.ReadAsStreamAsync();
branches = await JsonSerializer.DeserializeAsync
<IEnumerable<GitHubBranch>>(responseStream);
}
else
{
getBranchesError = true;
}
shouldRender = true;
}
public class GitHubBranch
{
[JsonPropertyName("name")]
public string? Name { get; set; }
}
}
В предыдущем примере для C# 12 или более поздней версии для переменной создается пустой [] массив (branches). Для более ранних версий C#, скомпилированных с помощью пакета SDK до .NET 8, создайте пустой массив (Array.Empty<GitHubBranch>()).
Дополнительные рабочие примеры см. в примере отправки файлов на стороне сервера, который отправляет файлы в контроллер веб-API в статье ASP.NET Core Blazor отправки файлов.
Абстракции служб для вызовов веб-API
Этот раздел применяется к Blazor Web Apps, которые обеспечивают поддержку веб-API в серверном проекте или преобразуют запросы веб-API к внешнему API.
При использовании интерактивных режимов webAssembly и автоматического отрисовки компоненты по умолчанию создаются предварительно. Автокомпоненты также изначально интерактивно отображаются на сервере перед загрузкой Blazor пакета клиенту и активацией клиентской среды выполнения. Это означает, что компоненты, использующие эти режимы отрисовки, должны быть разработаны таким образом, чтобы они успешно выполнялись как от клиента, так и от сервера. Если компонент должен выполнить вызов API, основанный на серверном проекте, или перенаправить запрос к внешнему веб-API (находящемуся за пределами области клиента Blazor Web App), рекомендуется абстрагировать этот вызов API с использованием интерфейса службы и реализовать как клиентскую, так и серверную версии этой службы.
- Версия клиента вызывает веб-API с предварительно настроенной HttpClientконфигурацией.
- Версия сервера обычно может напрямую получить доступ к ресурсам на стороне сервера. Внедрение HttpClient на сервере, который выполняет обратные вызовы к серверу, не рекомендуется, так как сетевой запрос обычно является ненужным. Кроме того, API может быть внешним для проекта сервера, но абстракция службы для сервера требуется для преобразования запроса каким-то образом, например для добавления маркера доступа к прокси-запросу.
При использовании режима WebAssembly вы также можете отключить предварительную отрисовку, чтобы компоненты рендерились только на клиенте. Дополнительные сведения см. в разделе Prerender ASP.NET Core Razor компоненты.
Примеры (примеры приложений):
- Веб-API для списка фильмов в приложении-примере
BlazorWebAppCallWebApi. - Веб-API для стримингового рендеринга погодных данных в примере приложения
BlazorWebAppCallWebApi_Weather. - Данные о погоде возвращаются клиенту в примерах приложений, которые используют либо
BlazorWebAppOidc(ненаборный шаблон), либоBlazorWebAppOidcBff(BFF-шаблон). Эти приложения демонстрируют безопасные (веб-) вызовы API. Дополнительные сведения см. в разделе Secure ASP.NET Core Blazor Web App с помощью OpenID Connect (OIDC).
Blazor Web App внешние веб-API
Этот раздел относится к Blazor Web Appам, которые вызывают веб-API, поддерживаемый отдельным (внешним) проектом, возможно размещённым на другом сервере.
Blazor Web Appобычно предварительно отрисованные клиентские компоненты WebAssembly, и компоненты Auto рендерятся на сервере во время статической или интерактивной отрисовки на стороне сервера (SSR).
HttpClient Службы по умолчанию не регистрируются в Blazor Web App основном проекте. Если приложение выполняется только с HttpClient услугами, зарегистрированными в .Client проекте, как описано в разделе Добавление службы HttpClient, выполнение приложения приводит к ошибке во время выполнения:
InvalidOperationException: не удается указать значение свойства "Http" в типе "... {COMPONENT}'. Зарегистрированная служба типа System.Net.Http.HttpClient отсутствует.
Используйте любой из следующих подходов:
Добавьте службы в проект сервера, чтобы сделать их доступными во время SSR. Используйте следующую регистрацию службы в файле
Programпроекта сервера:builder.Services.AddHttpClient();HttpClient службы предоставляются общей платформой, поэтому ссылка на пакет в файле проекта приложения не требуется.
Пример. Веб-API списка todo в
BlazorWebAppCallWebApiпримере приложенияЕсли предварительный рендеринг не требуется для компонента WebAssembly, вызывающего веб-API, отключите предварительный рендеринг, следуя инструкциям в Prerender ASP.NET Core Razor компоненты. Если вы используете этот подход, вам не нужно добавлять HttpClient службы в основной проект Blazor Web App , так как компонент не предопределен на сервере.
Дополнительные сведения см. в разделе "Не удается разрешить клиентские службы на время пререндеринга" статьи о пререндеринге.
Сценарии на стороне клиента для вызова внешних веб-API
Клиентские компоненты вызывают внешние веб-API, используя экземпляры HttpClient, которые обычно создаются с использованием заранее настроенного HttpClient, зарегистрированного в файле Program.
builder.Services.AddScoped(sp =>
new HttpClient
{
BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
});
Следующий компонент Razor выполняет запрос к веб-API о ветвях GitHub, аналогичный примеру Basic Usage из статьи HTTP-запросы с IHttpClientFactory - ASP.NET Core.
CallWebAPI.razor:
@page "/call-web-api"
@using System.Text.Json
@using System.Text.Json.Serialization
@inject HttpClient Client
<h1>Call web API from a Blazor WebAssembly Razor component</h1>
@if (getBranchesError || branches is null)
{
<p>Unable to get branches from GitHub. Please try again later.</p>
}
else
{
<ul>
@foreach (var branch in branches)
{
<li>@branch.Name</li>
}
</ul>
}
@code {
private IEnumerable<GitHubBranch>? branches = [];
private bool getBranchesError;
private bool shouldRender;
protected override bool ShouldRender() => shouldRender;
protected override async Task OnInitializedAsync()
{
using var request = new HttpRequestMessage(HttpMethod.Get,
"https://api.github.com/repos/dotnet/AspNetCore.Docs/branches");
request.Headers.Add("Accept", "application/vnd.github.v3+json");
request.Headers.Add("User-Agent", "HttpClientFactory-Sample");
using var response = await Client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
using var responseStream = await response.Content.ReadAsStreamAsync();
branches = await JsonSerializer.DeserializeAsync
<IEnumerable<GitHubBranch>>(responseStream);
}
else
{
getBranchesError = true;
}
shouldRender = true;
}
public class GitHubBranch
{
[JsonPropertyName("name")]
public string? Name { get; set; }
}
}
В предыдущем примере для C# 12 или более поздней версии для переменной создается пустой [] массив (branches). Для более ранних версий C#, скомпилированных с помощью пакета SDK до .NET 8, создайте пустой массив (Array.Empty<GitHubBranch>()).
Чтобы защитить код и данные .NET/C#, используйте функции ASP.NET Core Data Protection с серверным веб-API на базе ASP.NET Core. Клиентское Blazor WebAssembly приложение вызывает серверный веб-API для безопасных функций приложений и обработки данных.
Blazor WebAssembly приложения часто не могут осуществлять прямые вызовы между различными источниками веб-API из-за механизма безопасности CORS (совместного использования междоменных запросов). Обычное исключение выглядит следующим образом:
Доступ к запросу по адресу "{URL}" из источника "https://localhost:{PORT}'" был заблокирован политикой CORS: в запрошенном ресурсе отсутствует заголовок Access-Control-Allow-Origin. Если непрозрачный ответ служит вашим потребностям, задайте для режима запроса значение no-cors, чтобы получить ресурс с отключенным CORS.
Даже если вы вызываете SetBrowserRequestMode с полем BrowserRequestModeNoCors (1), которое пытается обойти предыдущее исключение, запрос часто завершается ошибкой из-за ограничений CORS в источнике веб-API, например ограничение, которое разрешает вызовы только из определенных источников или ограничение, которое предотвращает запросы JavaScript fetch из браузера. Единственный способ, чтобы такие вызовы были успешными, заключается в том, что веб-API, которое вы вызываете, должно разрешить вашему источнику вызывать его источник с правильной конфигурацией CORS. Большинство внешних веб-API не позволяют настраивать политики CORS. Чтобы справиться с этим ограничением, выполните любую из следующих стратегий:
Поддерживайте собственное серверное веб-API ASP.NET Core на стороне сервера. Клиентское Blazor WebAssembly приложение вызывает ваше веб-API на стороне сервера, и ваше веб-API отправляет запрос из серверного кода на C# (а не из браузера) к внешнему веб-API с правильными заголовками CORS, возвращая результат в клиентское Blazor WebAssembly приложение.
Используйте службу прокси-сервера для прокси-запроса из клиентского приложения Blazor WebAssembly в внешний веб-API. Прокси-служба использует серверное приложение для выполнения запроса от имени клиента и возвращает результат после успешного вызова. В следующем примере, базирующемся на CORS PROXY от CloudFlare, заполнитель
{REQUEST URI}является URI запроса:@using System.Net @inject IHttpClientFactory ClientFactory ... @code { public async Task CallApi() { var client = ClientFactory.CreateClient(); var urlEncodedRequestUri = WebUtility.UrlEncode("{REQUEST URI}"); using var request = new HttpRequestMessage(HttpMethod.Get, $"https://corsproxy.io/?{urlEncodedRequestUri}"); using var response = await client.SendAsync(request); ... } }
Добавьте службу HttpClient
Рекомендации в этом разделе относятся к сценариям на стороне клиента.
Клиентские компоненты вызывают веб-API с помощью предварительно настроенной HttpClient службы, которая сосредоточена на выполнении запросов обратно на сервер источника. Дополнительные конфигурации службы HttpClient для других веб-API можно создать в коде разработчика. Запросы формируются с использованием вспомогательных средств JSON Blazor или HttpRequestMessage. Запросы могут включать в себя конфигурацию параметра Fetch API.
Примеры конфигурации в этом разделе полезны только при вызове одного веб-API для одного HttpClient экземпляра в приложении. Когда приложение должно вызывать несколько веб-API, каждый из которых имеет собственный базовый адрес и конфигурацию, можно применить следующие подходы, описанные в следующих двух разделах этой статьи:
-
Названо
HttpClientсIHttpClientFactory: каждому веб-API присваивается уникальное имя. Если код приложения или Razor компонент вызывает веб-API, он использует именованный HttpClient экземпляр для вызова. -
Типизированный
HttpClient: каждый веб-API типизирован. Если код приложения или Razor компонент вызывает веб-API, он использует типизированный HttpClient экземпляр для вызова.
В файле Program добавьте службу HttpClient, если она еще не добавлена из шаблона проекта Blazor, использованного для создания приложения.
builder.Services.AddScoped(sp =>
new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
В предыдущем примере устанавливается базовый адрес с помощью builder.HostEnvironment.BaseAddress (IWebAssemblyHostEnvironment.BaseAddress), который получает базовый адрес приложения и обычно задается исходя из значения тега <base>href на хост-странице.
Наиболее распространенными случаями использования собственного базового адреса клиента являются:
- Клиентский проект (
.Client) клиента Blazor Web App (.NET 8 или более поздней версии) выполняет вызовы веб-API из компонентов WebAssembly или кода, который выполняется на клиенте в WebAssembly, к API в серверном приложении. - Клиентский проект (Client) приложения, размещённого на сервере Blazor WebAssembly, выполняет веб-API запросы к серверному проекту (Server). Обратите внимание, что шаблон проекта hosted 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") });
Названный HttpClient с IHttpClientFactory
Поддерживаются службы IHttpClientFactory и конфигурация именованного объекта HttpClient.
Note
Вместо именованного класса HttpClient из IHttpClientFactory можно использовать типизированный класс HttpClient. Дополнительные сведения см. в разделе Типы HttpClient.
Добавьте пакет NuGet Microsoft.Extensions.Http в приложение.
Note
Рекомендации по добавлению пакетов в приложения .NET можно найти в статьях раздела Установка и управление пакетами на странице Потребление пакетов (документация 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.BaseAddress (IWebAssemblyHostEnvironment.BaseAddress), который получает базовый адрес для клиентского приложения и обычно извлекается из значения тега <base> на хост-странице.
Наиболее распространенными случаями использования собственного базового адреса клиента являются:
- Клиентский проект (
.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 см. в разделе Use API Graph with ASP.NET Core Blazor WebAssembly.
Для демонстрации работы в клиентском приложении, основанной на вызове Microsoft Graph с именем HttpClient, см. раздел Использование API Graph с ASP.NET Core Blazor WebAssembly (Use API Graph with ASP.NET Core).
Введено HttpClient
Для возврата данных из одной или нескольких конечных точек веб-API типизированный класс HttpClient использует один или несколько экземпляров класса HttpClient приложения (заданных по умолчанию или именованных).
Note
Вместо типизированного HttpClient можно использовать именованный HttpClient из IHttpClientFactory. Дополнительные сведения см. в разделе Называется HttpClient с IHttpClientFactory.
Добавьте пакет NuGet Microsoft.Extensions.Http в приложение.
Note
Рекомендации по добавлению пакетов в приложения .NET можно найти в статьях раздела Установка и управление пакетами на странице Потребление пакетов (документация 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, описанным ниже.
В предыдущем примере задается базовый адрес с помощью builder.HostEnvironment.BaseAddress (IWebAssemblyHostEnvironment.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.
Доступ к службам за пределами HttpClientобласти
IHttpClientFactory создает DelegatingHandler экземпляры в отдельной области внедрения зависимостей (DI) из приложения. Если вы внедряете службу с областью действия в производный DelegatingHandler тип, обработчик не имеет доступа к службе из Blazor канала.
Пример того, как получить доступ к службе в промежуточном слое исходящего запроса с помощью обработчика области приложения или обработчика активности цепи, см. в разделе Blazor Web App.
Дополнительные сведения о экземплярах DelegatingHandler см. в разделе HTTP-запросы с IHttpClientFactory — ASP.NET Core.
HttpRequestMessageУдаление , HttpResponseMessageиHttpClient
Если у HttpRequestMessage нет тела, его не нужно явно удалять. Однако его можно удалить с помощью одного из следующих шаблонов:
usingобъявление (C# 8 или позже):using var request = new HttpRequestMessage(...);-
using (var request = new HttpRequestMessage(...)) { ... }
Рекомендуется утилизировать каждый HttpRequestMessage после каждого использования по следующим причинам:
- Чтобы повысить производительность, избегайте использования финализаторов.
- Он укрепляет код на будущее на случай, если когда-либо будет добавлено тело запроса в HttpRequestMessage, который изначально его не содержал.
- Чтобы, возможно, избежать функциональных проблем, если делегирующий обработчик ожидает вызова Dispose/DisposeAsync.
- Проще применять общее правило везде, чем пытаться помнить конкретные случаи.
Всегда удалять HttpResponseMessage экземпляры.
Никогда не удалять HttpClient экземпляры, созданные путем вызова CreateClient , так как они управляются платформой.
Example:
using var request = new HttpRequestMessage(HttpMethod.Get, "/weather-forecast");
var client = clientFactory.CreateClient("ExternalApi");
using var response = await client.SendAsync(request);
Предварительно обработанные данные
При предварительной подготовке компоненты дважды отображаются: сначала статически, а затем интерактивно. Состояние не передается автоматически от предварительно отрисованного компонента к интерактивному. Если компонент выполняет асинхронные операции инициализации и отрисовывает разное содержимое для различных состояний во время инициализации, например, индикатор прогресса "Загрузка...", вы можете заметить мерцание, когда компонент отрисовывается дважды.
Для этого можно управлять предварительно созданным состоянием с помощью API состояния сохраняемого компонента, что демонстрируется в примерах приложений
Note
API состояния сохраняемого компонента поддерживает только расширенную навигацию в .NET 10 или более поздней версии. Для приложений, предназначенных для .NET 8 или .NET 9, можно отключить расширенную навигацию по ссылкам на страницу с атрибутом data-enhance-nav, установленным для false. Дополнительные сведения см. в разделе ASP.NET Core Blazor навигации.
Вспомогательные инструменты JSON
ПакетSystem.Net.Http.Json предоставляет расширенные методы для System.Net.Http.HttpClient и System.Net.Http.HttpContent, которые выполняют автоматическую сериализацию и десериализацию с помощьюSystem.Text.Json. Пакет System.Net.Http.Json предоставляется общей платформой .NET и не требует добавления ссылки на пакет в приложение.
HttpClient доступен в качестве предварительно настроенной службы для отправки запросов обратно к серверу-источнику. HttpClient и вспомогательные функции JSON (System.Net.Http.Json.HttpClientJsonExtensions) также используются для вызова сторонних конечных точек API. HttpClient реализуется с помощью Fetch 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.
Note
Дополнительные сведения см. в разделе JsonPatch в веб-API ASP.NET Core.
В следующем примере PatchAsJsonAsync получает документ JSON PATCH в виде строки обычного текста с экранируемыми кавычками:
await Http.PatchAsJsonAsync(
$"todoitems/{id}",
"[{\"operationType\":2,\"path\":\"/IsComplete\",\"op\":\"replace\",\"value\":true}]");
Начиная с C# 11 (.NET 7), можно создавать строку JSON как сырой строковый литерал. Укажите синтаксис JSON с помощью поля StringSyntaxAttribute.Json для атрибута и[StringSyntax] для средств анализа кода.
@using System.Diagnostics.CodeAnalysis
...
@code {
[StringSyntax(StringSyntaxAttribute.Json)]
private const string patchOperation =
"""[{"operationType":2,"path":"/IsComplete","op":"replace","value":true}]""";
...
await Http.PatchAsJsonAsync($"todoitems/{id}", patchOperation);
}
PatchAsJsonAsync возвращает HttpResponseMessage. Чтобы десериализовать содержимое JSON из ответного сообщения, используйте метод расширения ReadFromJsonAsync. В следующем примере данные элемента JSON задачи считываются в виде массива. Пустой массив создается, если данные элемента не возвращаются методом, поэтому content не имеет значения NULL после выполнения инструкции:
using var response = await Http.PatchAsJsonAsync(...);
var content = await response.Content.ReadFromJsonAsync<TodoItem[]>() ??
Array.Empty<TodoItem>();
Представленный с отступами, интервалами и незащищенными кавычками, не кодированный PATCH документ отображается как следующий JSON:
[
{
"operationType": 2,
"path": "/IsComplete",
"op": "replace",
"value": true
}
]
Чтобы упростить создание документов PATCH в приложении, выдавающем запросы PATCH, приложение может использовать поддержку .NET JSON PATCH, как показано в следующем руководстве.
Установите пакет NuGet Microsoft.AspNetCore.JsonPatch.SystemTextJson и используйте функции API пакета для создания JsonPatchDocument для запроса PATCH.
Note
Рекомендации по добавлению пакетов в приложения .NET можно найти в статьях раздела Установка и управление пакетами на странице Потребление пакетов (документация NuGet). Проверьте правильность версий пакета на сайте NuGet.org.
Добавьте директивы @using для пространств имен System.Text.Json, System.Text.Json.Serialization и Microsoft.AspNetCore.JsonPatch.SystemTextJson в начало компонента Razor:
@using System.Text.Json
@using System.Text.Json.Serialization
@using Microsoft.AspNetCore.JsonPatch.SystemTextJson
Создайте JsonPatchDocument для TodoItem с IsComplete, установленного для true, с помощью метода JsonPatchDocument.Replace.
var patchDocument = new JsonPatchDocument<TodoItem>()
.Replace(p => p.IsComplete, true);
Установите пакет NuGet Microsoft.AspNetCore.JsonPatch и используйте функции API пакета для создания JsonPatchDocument для запроса PATCH.
Note
Рекомендации по добавлению пакетов в приложения .NET можно найти в статьях раздела Установка и управление пакетами на странице Потребление пакетов (документация NuGet). Проверьте правильность версий пакета на сайте NuGet.org.
Добавьте директивы @using для пространств имен System.Text.Json, System.Text.Json.Serialization и Microsoft.AspNetCore.JsonPatch в начало компонента Razor:
@using System.Text.Json
@using System.Text.Json.Serialization
@using Microsoft.AspNetCore.JsonPatch
Создайте JsonPatchDocument для TodoItem с IsComplete, установленного для true, с помощью метода 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 в веб-API ASP.NET Core, чтобы добавить действие контроллера PATCH в веб-API. Кроме того, обработка запросов PATCH может быть реализована как минимальный API с помощью следующих шагов.
Добавьте ссылку на пакет NuGet Microsoft.AspNetCore.JsonPatch.SystemTextJson в веб-приложение API.
В файле Program добавьте директиву @using для пространства имен Microsoft.AspNetCore.JsonPatch.SystemTextJson:
using Microsoft.AspNetCore.JsonPatch.SystemTextJson;
Добавьте ссылку на пакет NuGet Microsoft.AspNetCore.Mvc.NewtonsoftJson в веб-приложение API.
Note
Нет необходимости добавлять ссылку на пакет 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.NotFound();
});
Warning
Как и в других примерах, приведенных в статье JsonPatch в веб-API ASP.NET Core, предыдущий API PATCH не защищает веб-API от атак чрезмерной отправки данных. Дополнительные сведения см. в разделе Tutorial: создание веб-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}");
Потоковая передача запросов на стороне клиента
Для браузеров на основе Chromium (например, Google Chrome и Microsoft Edge), использующих протокол HTTP/2 и HTTPS, на стороне клиента компонент
Чтобы включить потоковую передачу запросов, задайте для SetBrowserRequestStreamingEnabled значение true на HttpRequestMessage.
В следующем примере отправки файла:
-
content— это HttpContentфайла. -
/Filesave— это конечная точка веб-API. -
Http— это HttpClient.
using var request = new HttpRequestMessage(HttpMethod.Post, "/Filesave");
request.SetBrowserRequestStreamingEnabled(true);
request.Content = content;
using var response = await Http.SendAsync(request);
Потоковые запросы:
- Требовать использования протокола HTTPS и не поддерживать работу с HTTP/1.x.
- Включите текст, но не заголовок
Content-Length. CORS с предварительным запросом требуется для междоменных потоковых запросов.
Дополнительные сведения о загрузке файлов с компонентом InputFile см. в разделе ASP.NET Core Blazor загрузка файлов и пример в разделе Загрузка файлов на сервер с клиентской визуализацией (CSR).
CookieУчетные данные запроса, основанные на
Руководство в этом разделе относится к сценариям на стороне клиента, которые используют проверку подлинности cookie.
Для аутентификации на основе cookie, которая считается более безопасной, чем аутентификация на основе токенов, учетные данные cookie можно отправлять с каждым запросом к веб-API, вызывая AddHttpMessageHandler с помощью DelegatingHandler на предварительно настроенном HttpClient. Обработчик настраивает SetBrowserRequestCredentials с помощью BrowserRequestCredentials.Include, который инструктирует браузер отправлять учетные данные с каждым запросом, например, заголовки куки или заголовки 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);
}
}
Note
Инструкции по доступу к AuthenticationStateProvider из DelegatingHandler см. в разделе ASP.NET Core на стороне сервера и Blazor Web App дополнительные сценарии безопасности.
В CookieHandler файле регистрируется Program.
builder.Services.AddTransient<CookieHandler>();
Обработчик сообщений добавляется к любой предварительно настроенной HttpClient конфигурации, требующей cookie проверки подлинности:
builder.Services.AddHttpClient(...)
.AddHttpMessageHandler<CookieHandler>();
Демонстрация см. в разделе Secure ASP.NET Core Blazor WebAssembly с ASP.NET Core Identity.
При создании HttpRequestMessage задайте данные авторизации браузера и заголовок напрямую:
using var request = new HttpRequestMessage() { ... };
request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);
request.Headers.Add("X-Requested-With", [ "XMLHttpRequest" ]);
Использование обработчика маркеров для вызовов веб-API
Blazor Web AppС проверкой подлинности OIDC можно использовать подход обработчика маркеров для отправки исходящих запросов, чтобы обеспечить безопасность внешних вызовов веб-API. Этот подход используется приложениями BlazorWebAppOidc и BlazorWebAppOidcServer, описанными в разделе "Примеры приложений".
Дополнительные сведения см. на следующих ресурсах:
- ASP.NET Core на стороне сервера и Blazor Web App дополнительные сценарии безопасности
- Обеспечить безопасную работу ASP.NET Core Blazor Web App с OpenID Connect (OIDC)
Платформа идентификации Microsoft для вызовов веб-API
Blazor Web App, которые используют платформа удостоверений Майкрософт с Microsoft Identity веб-пакетами для Microsoft Entra ID могут упростить вызовы веб-API с помощью API, предоставляемого Microsoft.Identity.Web.DownstreamApi пакетом NuGet.
Note
Рекомендации по добавлению пакетов в приложения .NET можно найти в статьях раздела Установка и управление пакетами на странице Потребление пакетов (документация NuGet). Проверьте правильность версий пакета на сайте NuGet.org.
В файле параметров приложения (appsettings.json) укажите базовый URL-адрес и области. В следующем примере местозаполнитель {BASE ADDRESS} — это базовый URL-адрес веб-API. Указана одна область с URI идентификатора приложения ({APP ID URI} заполнитель) и именем области ({SCOPE NAME} заполнителя):
"DownstreamApi": {
"BaseUrl": "{BASE ADDRESS}",
"Scopes": [ "{APP ID URI}/{SCOPE NAME}" ]
}
Example:
"DownstreamApi": {
"BaseUrl": "https://localhost:7277",
"Scopes": [ "api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get" ]
}
В файле приложения Program вызовите:
- EnableTokenAcquisitionToCallDownstreamApi: позволяет получать токены для вызова веб API.
-
AddDownstreamApi: Веб-пакеты Microsoft Identity предоставляют API для создания именованной последующей веб-службы для выполнения вызовов API.
IDownstreamApi внедряется в серверный класс, который используется для вызова CallApiForUserAsync для получения данных о погоде из внешнего веб-API (
MinimalApiJwtпроекта). - AddDistributedTokenCaches: добавляет кэши распределенных токенов .NET в коллекцию служб.
- AddDistributedMemoryCache: добавляет реализацию IDistributedCache по умолчанию, в которой хранятся элементы кэша в памяти.
- Настройте параметры кэша распределенных маркеров (MsalDistributedTokenCacheAdapterOptions):
- В процессе разработки для отладки можно отключить кэш L1, установив для этого значение DisableL1Cache
true. Не забудьте сбросить его обратно вfalseв производственной среде. - Задайте максимальный размер кэша L1,
L1CacheOptions.SizeLimitчтобы предотвратить перерасход памяти сервера. Значение по умолчанию — 500 МБ. - Для целей отладки в разработке, вы можете отключить шифрование токенов в состоянии покоя, установив Encrypt на
false, которое является значением по умолчанию. Не забудьте сбросить его обратно вtrueв производственной среде. - Установите вытеснение токена из кэша SlidingExpiration. Значение по умолчанию — 1 час.
- Дополнительные сведения, включая рекомендации по обратному вызову для сбоев кэша L2 (OnL2CacheFailure) и асинхронных операций записи кэша L2 (EnableAsyncL2Write), см. в разделе MsalDistributedTokenCacheAdapterOptions и сериализация кэша маркеров: распределенные кэши маркеров.
- В процессе разработки для отладки можно отключить кэш L1, установив для этого значение DisableL1Cache
Вы можете зашифровать кэш и всегда делать это в рабочей среде.
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()
.AddDownstreamApi("DownstreamApi",
builder.Configuration.GetSection("DownstreamApi"))
.AddDistributedTokenCaches();
// Requires the 'Microsoft.Extensions.Caching.Memory' NuGet package
builder.Services.AddDistributedMemoryCache();
builder.Services.Configure<MsalDistributedTokenCacheAdapterOptions>(
options =>
{
// The following lines that are commented out reflect
// default values. We recommend overriding the default
// value of Encrypt to encrypt tokens at rest.
//options.DisableL1Cache = false;
//options.L1CacheOptions.SizeLimit = 500 * 1024 * 1024;
options.Encrypt = true;
//options.SlidingExpiration = TimeSpan.FromHours(1);
});
Кэши распределенных маркеров в памяти создаются при вызове AddDistributedTokenCaches , чтобы обеспечить базовую реализацию, доступную для кэширования распределенных маркеров.
Рабочие веб-приложения и веб-API должны использовать рабочий кэш распределенных маркеров (например, Redis, Microsoft SQL Server, Microsoft Azure Cosmos DB).
Note
Для локальной разработки и тестирования на одном компьютере можно использовать кэши маркеров в памяти вместо распределенных кэшей маркеров:
builder.Services.AddInMemoryTokenCaches();
Позже, в период разработки и тестирования, используйте рабочий распределенный провайдер кэша токенов.
AddDistributedMemoryCache добавляет реализацию IDistributedCache по умолчанию, которая хранит элементы кэша в памяти и используется Microsoft Identity Web для кэширования маркеров.
AddDistributedMemoryCache требует ссылки на Microsoft.Extensions.Caching.Memory пакет NuGet.
Note
Рекомендации по добавлению пакетов в приложения .NET можно найти в статьях раздела Установка и управление пакетами на странице Потребление пакетов (документация NuGet). Проверьте правильность версий пакета на сайте NuGet.org.
Сведения о настройке поставщика распределенного кэша в рабочей среде см. в разделе Распределённое кэширование в ASP.NET Core.
Warning
Всегда заменяйте распределенные кэши токенов в памяти на реального поставщика кэша токенов при развертывании приложения в рабочей среде. Если не удается внедрить поставщика кэша распределенных маркеров в промышленной среде, производительность приложения может значительно ухудшиться.
Дополнительные сведения см. в разделе сериализация кэша маркеров: распределенные кэши. Однако приведенные примеры кода не применяются к приложениям ASP.NET Core, которые настраивают распределенные кэши с помощью AddDistributedMemoryCache, а не AddDistributedTokenCache.
Используйте общедоступное кольцо ключей защиты данных в рабочей среде, чтобы экземпляры приложения на серверах в веб-ферме могли расшифровать маркеры, когда для MsalDistributedTokenCacheAdapterOptions.Encrypt задано значение true.
Note
Для ранней разработки и локального тестирования на одном компьютере можно задать значение Encrypt как false, а позже настроить общее кольцо ключей защиты данных:
options.Encrypt = false;
Позже в период разработки и тестирования включите шифрование маркеров и установите общий круг ключей защиты данных.
В следующем примере показано, как использовать Хранилище BLOB-объектов Azure и Azure Key Vault (PersistKeysToAzureBlobStorage/ProtectKeysWithAzureKeyVault) для общего круга ключей. Конфигурации служб — это базовые сценарии для демонстрационных целей. Перед развертыванием рабочих приложений изучите службы Azure и воспользуйтесь рекомендациями из выделенных наборов документации по службам Azure, ссылки на которые приведены в конце этого раздела.
Добавьте следующие пакеты в серверный проект:Blazor Web App
Note
Рекомендации по добавлению пакетов в приложения .NET можно найти в статьях раздела Установка и управление пакетами на странице Потребление пакетов (документация NuGet). Проверьте правильность версий пакета на сайте NuGet.org.
Note
Прежде чем продолжить действия, убедитесь, что приложение зарегистрировано в Microsoft Entra.
Настройте Хранилище BLOB-объектов Azure для поддержания ключей защиты данных. Следуйте инструкциям в Key storage providers in ASP.NET Core.
Настройте Azure Key Vault для шифрования неактивных ключей защиты данных. Следуйте инструкциям в Configure ASP.NET Core Data Protection.
Используйте следующий код в Program файле, где зарегистрированы службы:
TokenCredential? credential;
if (builder.Environment.IsProduction())
{
credential = new ManagedIdentityCredential("{MANAGED IDENTITY CLIENT ID}");
}
else
{
// Local development and testing only
DefaultAzureCredentialOptions options = new()
{
// Specify the tenant ID to use the dev credentials when running the app locally
// in Visual Studio.
VisualStudioTenantId = "{TENANT ID}",
SharedTokenCacheTenantId = "{TENANT ID}"
};
credential = new DefaultAzureCredential(options);
}
builder.Services.AddDataProtection()
.SetApplicationName("{APPLICATION NAME}")
.PersistKeysToAzureBlobStorage(new Uri("{BLOB URI}"), credential)
.ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), credential);
{MANAGED IDENTITY CLIENT ID}: Идентификатор клиента Azure Managed Identity (GUID).
{TENANT ID}: идентификатор клиента.
{APPLICATION NAME}: SetApplicationName задает уникальное имя этого приложения в системе защиты данных. Значение должно совпадать между развертываниями приложения.
{BLOB URI}: полный универсальный код ресурса (URI) к файлу ключа. URI создается службой служба хранилища Azure, когда вы создаёте файл ключа. Не используйте SAS.
{KEY IDENTIFIER}: Azure Key Vault идентификатор ключа, используемый для шифрования ключей. Политика доступа позволяет приложению получать доступ к хранилищу ключей с разрешениями Get, Unwrap Key и Wrap Key. Идентификатор ключа получается из ключа на портале Entra или Azure после его создания. Если вы включаете автоматическое обновление ключа в хранилище ключей, убедитесь, что в конфигурации хранилища ключей приложения используется идентификатор ключа без указания версии. В конце этого идентификатора не должно быть GUID ключа (например, https://contoso.vault.azure.net/keys/data-protection).
Note
В средах, отличных от Production, предыдущий пример использует DefaultAzureCredential для упрощения проверки подлинности при разработке приложений, которые развертываются в Azure путем объединения учетных данных, используемых в средах размещения Azure с учетными данными, используемыми в локальной разработке. При переходе к рабочей среде альтернативный вариант является лучшим выбором, как показано в предыдущем примере ManagedIdentityCredential. Дополнительные сведения см. в разделе Аутентификация размещенных в Azure приложений .NET с Azure ресурсами с помощью системного управляемого удостоверения.
Внедрение IDownstreamApi и вызов CallApiForUserAsync при вызове от имени пользователя:
internal sealed class ServerWeatherForecaster(IDownstreamApi downstreamApi) : IWeatherForecaster
{
public async Task<IEnumerable<WeatherForecast>> GetWeatherForecastAsync()
{
var response = await downstreamApi.CallApiForUserAsync("DownstreamApi",
options =>
{
options.RelativePath = "/weather-forecast";
});
return await response.Content.ReadFromJsonAsync<WeatherForecast[]>() ??
throw new IOException("No weather forecast!");
}
}
Этот подход используется приложениями BlazorWebAppEntra и BlazorWebAppEntraBff, описанными в разделе "Примеры приложений".
Дополнительные сведения см. на следующих ресурсах:
- поставщики хранилища ключей в ASP.NET Core
- Configure ASP.NET Core Data Protection
- Использовать Azure SDK для .NET в приложениях ASP.NET Core
- документация по Web API | платформе идентификации Microsoft
- Веб-API, который вызывает веб-API: вызов API: вариант 2. Вызов нижестоящего веб-API с вспомогательным классом
- IDownstreamApi
- Защитите ASP.NET Core Blazor Web App с помощью Microsoft Entra ID
- Размещение ASP.NET Core в веб-ферме: Защита данных
- документация Azure Key Vault
- документация служба хранилища Azure
- Предоставить доступ к ключам Key Vault, сертификатам и секретам с помощью управления доступом на основе ролей Azure.
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()
{
using var request = new HttpRequestMessage()
{
Method = new HttpMethod("POST"),
RequestUri = new Uri("https://localhost:10000/todoitems"),
Content =
JsonContent.Create(new TodoItem
{
Name = "My New Todo Item",
IsComplete = false
})
};
var tokenResult = await TokenProvider.RequestAccessToken();
if (tokenResult.TryGetToken(out var token))
{
request.Headers.Authorization =
new AuthenticationHeaderValue("Bearer", token.Value);
request.Content.Headers.TryAddWithoutValidation(
"x-custom-header", "value");
using var response = await Http.SendAsync(request);
var responseStatusCode = response.StatusCode;
responseBody = await response.Content.ReadAsStringAsync();
}
}
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
}
Blazor клиентская реализация HttpClient использует Fetch API и настраивает основные опции Fetch API для конкретного запроса с помощью методов расширения HttpRequestMessage и WebAssemblyHttpRequestMessageExtensions. Задайте дополнительные параметры с помощью более универсального метода расширения SetBrowserRequestOption. Blazor и базовый Fetch API напрямую не добавляют и не изменяют заголовки запросов. Дополнительные сведения о том, как агенты пользователей, такие как браузеры, взаимодействуют с заголовками, см. в документации внешнего агента пользователя и других веб-ресурсах.
Потоковая передача ответов включена по умолчанию.
Вызов HttpContent.ReadAsStreamAsync для HttpResponseMessage.Content (response.Content.ReadAsStreamAsync()) возвращает BrowserHttpReadStream (эталонный источник), а не MemoryStream.
BrowserHttpReadStream не поддерживает синхронные операции, например Stream.Read(Span<Byte>). Если код использует синхронные операции, вы можете отказаться от потоковой передачи ответов или скопировать Stream в MemoryStream самостоятельно.
Note
Ссылки на справочную документацию .NET обычно ведут на ветвь репозитория по умолчанию, которая представляет собой текущую разработку следующего релиза .NET. Чтобы выбрать тег для определенного выпуска, используйте выпадающий список «Переключение ветвей или тегов». Дополнительные сведения см. в разделе Как выбрать тег версии исходного кода ASP.NET Core (dotnet/AspNetCore.Docs #26205).
Чтобы отказаться от потоковой передачи ответов глобально, используйте любой из следующих подходов:
Добавьте свойство
<WasmEnableStreamingResponse>в файл проекта со значениемfalse:<WasmEnableStreamingResponse>false</WasmEnableStreamingResponse>Установите для переменной среды
DOTNET_WASM_ENABLE_STREAMING_RESPONSEзначениеfalseили0.
Чтобы отказаться от потоковой передачи ответов для отдельного запроса, задайте для SetBrowserResponseStreamingEnabled значение false на HttpRequestMessage (request в следующем примере):
request.SetBrowserResponseStreamingEnabled(false);
HTTP-ответ обычно помещается в буфер для выполнения операций синхронизации содержимого ответа. Чтобы включить поддержку потоковой передачи ответов, установите параметр SetBrowserResponseStreamingEnabled в true в поле HttpRequestMessage.
request.SetBrowserResponseStreamingEnabled(true);
По умолчанию устанавливается HttpCompletionOption.ResponseContentRead, что приводит к завершению HttpClient после прочтения всего ответа, включая содержимое. Чтобы использовать параметр SetBrowserResponseStreamingEnabled в больших файлах, задайте HttpCompletionOption.ResponseHeadersRead, чтобы избежать кэширования содержимого файла в памяти:
- using var response = await Http.SendAsync(request);
+ using var response = await Http.SendAsync(request,
+ HttpCompletionOption.ResponseHeadersRead);
Чтобы включить учетные данные в запрос независимо от источника, используйте метод расширения SetBrowserRequestCredentials.
request.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 ℃
@forecast.TemperatureF ℉
</li>
}
</ul>
}
<p>
@exceptionMessage
</p>
@code {
private WeatherForecast[]? forecasts;
private string? exceptionMessage;
protected override async Task OnInitializedAsync()
{
try
{
// The URI endpoint "WeatherForecast" is misspelled on purpose on the
// next line. See the preceding text for more information.
forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForcast");
}
catch (NotSupportedException exception)
{
exceptionMessage = exception.Message;
}
}
}
Note
Предыдущий пример приведен только в качестве демонстрации. Веб-API можно настроить для возврата JSON, даже если конечная точка не существует или на сервере возникает необработанное исключение.
Для получения дополнительной информации см. обработку ошибок в приложениях ASP.NET CoreBlazor.
Совместное использование ресурсов между источниками (CORS)
Безопасность браузера часто ограничивает веб-страницу от выполнения запросов к другому источнику, чем тот, который обслуживал веб-страницу. Это ограничение называется политика одного источника. Эта политика запрещает (но не предотвращает) чтение вредоносным сайтом конфиденциальных данных с другого сайта. Чтобы отправлять запросы из браузера в конечную точку с другим источником, конечная точка должна включить общий доступ к ресурсам между источниками (CORS).
Дополнительные сведения о запросах на стороне сервера см. в разделе Enable Cross-Origin Requests (CORS) в ASP.NET Core. Примеры статьи не относятся непосредственно к Razor сценариям компонентов, но статья полезна для обучения общим понятиям CORS.
Дополнительные сведения о запросах CORS на стороне клиента см. в разделе ASP.NET Core Blazor WebAssembly дополнительные сценарии безопасности.
Поддержка защиты от подделок
Чтобы добавить поддержку антифоргерии в HTTP-запрос, внедрите AntiforgeryStateProvider и добавьте RequestToken в коллекцию заголовков в качестве RequestVerificationToken.
@inject AntiforgeryStateProvider Antiforgery
private async Task OnSubmit()
{
var antiforgery = Antiforgery.GetAntiforgeryToken();
using var request = new HttpRequestMessage(HttpMethod.Post, "action");
request.Headers.Add("RequestVerificationToken", antiforgery.RequestToken);
using var response = await client.SendAsync(request);
...
}
Дополнительные сведения см. в разделе ASP.NET Core Blazor аутентификации и авторизации.
Примеры компонентов платформы Blazor для тестирования доступа к веб-API
Различные сетевые средства доступны для тестирования внутренних приложений веб-API напрямую, например Firefox Browser Developer. Источник справочной информации платформы Blazor содержит HttpClient тестовые средства, полезные для тестирования.
HttpClientTest ресурсы в репозитории dotnet/aspnetcore GitHub
Note
Ссылки на справочную документацию .NET обычно ведут на ветвь репозитория по умолчанию, которая представляет собой текущую разработку следующего релиза .NET. Чтобы выбрать тег для определенного выпуска, используйте выпадающий список «Переключение ветвей или тегов». Дополнительные сведения см. в разделе Как выбрать тег версии исходного кода ASP.NET Core (dotnet/AspNetCore.Docs #26205).
Примеры приложений
Примеры можно найти в приложениях из примеров в репозитории GitHub (
BlazorWebAppCallWebApi
Вызов внешнего веб-API списка дел, который не находится в Blazor Web App, из Blazor 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();
Вызовите внутренний API списка фильмов (внутри Blazor Web App), который находится в серверном проекте 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 не зависит от сети, и поэтому представляет собой стандартный интерфейс для операций 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();
}
Дополнительные сведения о том, как защитить данные фильма в этом сценарии, см. в примере данных о погоде, описанном в разделе "Безопасность данных в Blazor Web App" с использованием интерактивной автоматической отрисовки.
BlazorWebAppCallWebApi_Weather
Пример приложения для работы с погодными данными, использующего потоковую обработку данных.
BlazorWebAssemblyCallWebApi
Вызывает веб-API для списка задач из приложения Blazor WebAssembly.
-
Backend: веб API-приложение для ведения списка дел на основе минимальных API. -
BlazorTodo: Приложение Blazor WebAssembly, которое вызывает веб-API с предварительно настроенной системой HttpClient для операций CRUD со списком дел.
BlazorWebAssemblyStandaloneWithIdentity
Автономное приложение Blazor WebAssembly, защищенное с помощью ASP.NET Core Identity:
-
Backend: серверное веб-приложение API, которое поддерживает хранилище удостоверений пользователя для ASP.NET Core Identity. -
BlazorWasmAuth: автономное Blazor WebAssembly интерфейсное приложение с проверкой подлинности пользователя.
Решение демонстрирует вызов безопасного веб-API для следующих действий:
- Получение ролей пользователя, прошедших проверку подлинности.
- Обработка данных для всех пользователей, прошедших проверку подлинности.
- Обработка данных для авторизованных пользователей (пользователь должен находиться в роли
Manager) с помощью политики авторизации .
BlazorWebAppOidcBffAuto
Blazor Web App с глобальным интерактивным автоматическим рендерингом, который использует проверку подлинности OIDC с Microsoft Entra без использования пакетов, специфичных для Entra. В примере показано, как использовать обработчик токенов для выполнения вызовов внешнего защищенного веб-API.
BlazorWebAppOidcBffServer
Blazor Web App с глобальным рендерингом интерактивного сервера, использующего аутентификацию OIDC с Microsoft Entra без использования пакетов, специфичных для Entra. В примере показано, как передать маркер доступа для вызова внешнего защищенного веб-API.
BlazorWebAppOidcBffYarpAspire
A Blazor Web App с глобальной интерактивной автоматической отрисовкой, которая использует:
Решение включает демонстрацию безопасного получения данных о погоде через внешний веб-API на клиенте при рендеринге компонента с использованием интерактивного автоотрисовки.
BlazorWebAppEntraBff
Blazor Web App с глобальным автоматическим взаимодействием, использующим платформа удостоверений Майкрософт с Microsoft Identity веб-пакеты для Microsoft Entra ID. Решение включает демонстрацию безопасного получения данных о погоде через внешний веб-API на клиенте при рендеринге компонента с использованием интерактивного автоотрисовки.
BlazorWebAppEntraBffYarpAspire
Blazor Web App с глобальным автоматическим взаимодействием, использующим:
- платформа удостоверений Майкрософт с веб-пакетами Identity Microsoft для Microsoft Entra ID.
- YARP.
- Aspire.
Решение включает демонстрацию безопасного получения данных о погоде через внешний веб-API на клиенте при рендеринге компонента с использованием интерактивного автоотрисовки.
Дополнительные ресурсы
General
- Статья, посвященная общему доступу к ресурсам независимо от источника (CORS), на веб-сайте консорциума W3C
- Enable Cross-Origin Requests (CORS) в ASP.NET Core. Хотя содержимое относится к приложениям ASP.NET Core, а не к компонентам Razor, в статье рассматриваются общие понятия CORS.
- Защита данных в Blazor Web Appс помощью интерактивного автоматического рендеринга
- Статья, посвященная общему доступу к ресурсам независимо от источника (CORS), на веб-сайте консорциума W3C
- Enable Cross-Origin Requests (CORS) в ASP.NET Core. Хотя содержимое относится к приложениям ASP.NET Core, а не к компонентам Razor, в статье рассматриваются общие понятия CORS.
Смягчение атак чрезмерной отправкой данных
Веб-API могут быть уязвимы к атаке избыточной отправки, также известной как атака массового назначения данных. Атака переопубликования происходит, когда злоумышленник отправляет HTML-форму POST на сервер, который обрабатывает данные для свойств, не входящих в отображаемую форму, и которые разработчик не хочет позволять пользователям изменять. Термин "overposting" буквально означает, что вредоносный пользователь чрезмерно использовал метод POST с помощью формы.
Руководство по предотвращению атак чрезмерной отправки см. в статье Tutorial: создание веб-API на основе контроллера с помощью ASP.NET Core.
Server-side
- ASP.NET Core на стороне сервера и Blazor Web App дополнительные сценарии безопасности. Включает покрытие по использованию HttpClient для выполнения защищенных запросов веб-API.
- HTTP-запросы с IHttpClientFactory — ASP.NET Core
- Обеспечение HTTPS в ASP.NET Core
- Конфигурация конечной точки HTTPS Kestrel
Client-side
- ASP.NET Core Blazor WebAssembly дополнительные сценарии безопасности. Включает покрытие использования HttpClient для обеспечения безопасных запросов веб-API.
- Использование API Graph с ASP.NET Core Blazor WebAssembly
- Fetch API
ASP.NET Core