HttpClient в проекте Blazor WebAssembly

Последнее обновление: 01.12.2023

Для взаимодействия с сервером компоненты Blazor WebAssembly, как и компоненты уровня сервера, также используют класс HttpClient. Однако поскольку компоненты WebAssembly отрабатывают на клиенте, то в реальности для отправки запросов они будут использовать Fetch API браузера. Соответственно принцип установки и получения HttpClient в компонентах WebAssembly будет немного различаться.

Пусть у нас есть следующие проекты

Создание проекта ASP.NET Web API для тестирования приложения Blazor на C#

То есть у нас два проекта: главный проект BlazorApp и проект с компонентами WebAssembly - BlazorApp.Client. Поскольку на момент .NET 8 для хранения компонентов Blazor WebAssembly необходимо создавать дополнительный проект.

Настройка сервера

В главном проекте BlazorApp (на сервере) в файле Program.cs прописан следующий код:

using BlazorApp.Components;
using BlazorApp.Client;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorComponents()
    .AddInteractiveWebAssemblyComponents();  // поддержка компонентов WebAssembly

builder.Services.AddHttpClient();   // регистрируем сервис файбрики HttpClient

var app = builder.Build();

app.UseAntiforgery();

app.MapGet("/time", () => DateTime.Now.ToShortTimeString());

app.MapRazorComponents<App>()
    .AddInteractiveWebAssemblyRenderMode()    // рендеринг компонентов WebAssembly
    .AddAdditionalAssemblies(typeof(Home).Assembly); ;   // подключаем поиск компонентов из BlazorApp.Client


app.Run();

Здесь добавлены сервисы компонентов WebAssembly, определена поддержка рендеринга на стороне клиента и добавлен поиск компонентов в сборке, где находится компонент Home из второго проекта.

Для использования HttpClient регистрируем сервис фабрики:

builder.Services.AddHttpClient(); 

Для теста здесь также определена конечная точка, которая при обращении по пути "/time" возвращает текущее время.

app.MapGet("/time", () => DateTime.Now.ToShortTimeString());

В главном проекте BlazorApp в папке "Components" есть один компонент - корневой компонент App, который загружает компонент Home из второго проекта:

@page "/"
@using BlazorApp.Client

<!DOCTYPE html>
<html>
<head>
    <title>METANIT.COM</title>
    <meta charset="utf-8" />
</head>
<body>
    <Home />
    <script src="_framework/blazor.web.js"></script>
</body>
</html>

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

И для работы с HttpClient нам надо добавить данный объект в качестве сервиса в приложение. Для этого во втором проекте - BlazorApp.Client определим следующий файл Program.cs:

using Microsoft.AspNetCore.Components.WebAssembly.Hosting;

var builder = WebAssemblyHostBuilder.CreateDefault(args);

// добавляем HttpClient
builder.Services.AddScoped(sp =>
    new HttpClient
    {
        BaseAddress = new Uri("https://localhost:7066/")
    });

await builder.Build().RunAsync();

При добавлении HttpClient устанавливается свойство BaseAddress, которое определяет адрес веб-сервиса. В моем случае веб-приложение ASP.NET Core запущено по адресу "https://localhost:7066/".

После этого мы можем получить объект HttpClient в коде компонентов, как и любой другой сервис, с помощью внедрения зависимостей. Так, определим в проекте BlazorApp.Client следующий компонент Home:

@using Microsoft.AspNetCore.Components.Web
@using System.Net.Http.Json

@rendermode RenderMode.InteractiveWebAssembly
@inject HttpClient httpClient

<h2>Time: @time</h2>
<button @onclick="Submit">Click</button>

@code {
    string? time;
    async Task Submit()
    {
        var response = await httpClient.GetAsync("/time");
        time = await response.Content.ReadAsStringAsync();
    } 
}

Здесь по нажатию на кнопку отправляем Get-запрос к веб-сервису по пути "/time" и получаем ответ в переменную response:

var response = await httpClient.GetAsync("/time");

Далее считываем содержимое ответа в строку в переменную time, значение которой выводится в заголовке на веб-страницу:

time = await response.Content.ReadAsStringAsync();
Отправка запросов с помощью HttpClient в приложении Blazor Server на C#

В остальном работа с HttpClient будет идти также как и в принципе в .NET.

Отправка данных

Отправка запросов и получение ответов с помощью HttpClient в Blazor WebAssembly будет идти также, как и в целом в .NET - Отправка запросов с помощью HttpClient. Поэтому рассмотрим лишь один сценарий - отправку данных в POST-запросе. Пусть файл Program.cs в главном проекте BlazorApp выглядит следующим образом:

using BlazorApp.Components;
using BlazorApp.Client;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorComponents()
    ..AddInteractiveWebAssemblyComponents();

builder.Services.AddHttpClient();   // регистрируем сервис файбрики HttpClient
var app = builder.Build();

app.UseAntiforgery();

app.MapPost("/user", (Person user) =>
{
    // если длина имени меньше 3 или больше 20 символов
    if (user.Name.Length < 3 || user.Name.Length > 20)
        return Results.BadRequest(new { details = "Имя должно иметь не меньше 3 и не больше 20 символов" });
    // если возраст меньше 1 или больше 110
    if (user.Age < 1 || user.Age > 110)
        return Results.BadRequest(new { details = "Некорректный возраст" });
    // если все нормально, устанавливаем id для нового пользователя
    user.Id = Guid.NewGuid().ToString();
    // посылаем объект в виде json
    return Results.Json(user);
});

app.MapRazorComponents<App>()
    .AddInteractiveWebAssemblyRenderMode()
    .AddAdditionalAssemblies(typeof(Home).Assembly);


app.Run();


public class Person
{
    public string Id { get; set; } = "";
    public string Name { get; set; } = "";
    public int Age { get; set; }
}

Здесь предполагается, что клиент в POST-запросе по пути "/user" будет отправлять объект Person. При получении данных валидируем их (имя должно иметь от 3 до 20 символов, а возраст должен быть в диапазоне от 1 до 110). Если они не соответствуют некоторым ограничениям, то посылаем ошибку 400 и объект json с сообщением об ошибке:

if(user.Name.Length < 3 || user.Name.Length > 20) 
    return Results.BadRequest(new {details="Имя должно иметь не меньше 3 и не больше 20 символов" });
if (user.Age < 1 || user.Age > 110)
    return Results.BadRequest(new {details = "Некорректный возраст" });

Если данные корректны, то устанавливаем у объекта Person свойство Id и посылаем его в формате JSON обратно клиенту:

user.Id = Guid.NewGuid().ToString();
return Results.Json(user);

Для взаимодействия с этим веб-приложением в проекте BlazorApp.Client определим следующий компонент Home:

@using Microsoft.AspNetCore.Components.Web
@using System.Net.Http.Json

@rendermode RenderMode.InteractiveWebAssembly
@inject HttpClient httpClient

<div style="color:red;">@message</div>

<div>
    <p>
        Имя:<br />
        <input @bind-value="person.Name" />
    </p>
    <p>
        Возраст:<br />
        <input type="number" @bind-value="person.Age" />
    </p>
    <button @onclick="Submit">Click</button>
</div>

@code {
    string? message;
    Person person = new();
    async Task Submit()
    {
        message = "";
        var response = await httpClient.PostAsJsonAsync("https://localhost:7066/user", person);
        if (response.IsSuccessStatusCode)
        {
            var newPerson = await response.Content.ReadFromJsonAsync<Person>();
            if (newPerson != null) message = $"Создан объект Person с id = {newPerson.Id}";
        }
        else
        {
            var error = await response.Content.ReadFromJsonAsync<Error>();
            if (error != null) message = error.Details;
        }
    }
    class Error
    {
        public string Details { get; set; } = "";
    }
    class Person
    {
        public string Id { get; set; } = "";
        public string Name { get; set; } = "";
        public int Age { get; set; }
    }
}

Здесь определена форма с двумя полями ввода, которые привязаны к свойствам Name и Age объекта Person. По нажатию на кнопку срабатывает метод Submit, который в POST-запросе в виде кода json отправляет на сервер объект Person.

При успешном запросе (если сервер возвращает статусный код 2хх) получаем отправленный сервером объект Person с установленным Id и этот Id выводим в сообщении:

if (response.IsSuccessStatusCode)
{
    var newPerson = await response.Content.ReadFromJsonAsync<Person> ();
    if (newPerson != null) message = $"Создан объект Person с id = {newPerson.Id}";
}

Если же сервер возвратил ошибку (в нашем случае ошибку 400 при некорректности данных), получаем сообщение об ошибке в объект Error, и затем также выводим сообщение об ошибке на страницу:

else
{
    var error = await response.Content.ReadFromJsonAsync<Error>();
    if (error != null) message = error.Details;
}

Пример работы:

Создание проекта ASP.NET Web API для тестирования приложения Blazor на C#
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850