Базовый адрес HttpClient впервые становится нулевым в методе OnInitializedAsync в Blazor

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

builder.Services.AddHttpClient();

Я также добавил http-клиент в проект веб-сборки (клиента), как показано ниже:

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

Теперь проблема в том, что когда я внедряю HttpClient в компонент моей домашней страницы (в клиентском проекте) и пытаюсь использовать этот сервис в методе OnInitializedAsync, он в первый раз выдает исключение, говорящее, что базовый адрес не добавлен, но в методе OnAfterRenderAsync http клиент работает нормально с правильным базовым адресом.

Что мне следует сделать, чтобы использовать метод HttpClient в OnInitializedAsync?

Можете ли вы показать свой метод OnInitializedAsync?

mpoust 09.03.2024 16:57

Я испытываю точно такую ​​же проблему. Возможно, вам удалось найти решение? @РобинХан

Sheim 14.04.2024 10:46

Я добавил обходной путь в качестве ответа. Вы можете попробовать это @Sheim

Robin Khan 15.04.2024 14:41
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
3
252
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Помещение всего кода внутри проверки if для OnInitialized и OnParameterSet — это решение этой проблемы, как показано ниже:

[Inject] HttpClient httpClient { get; set; } = default!;
protected override async Task OnParametersSetAsync()
{
    if (httpClient.BaseAddress != null)
    {
        // all codes goes here specially which involves httpClient
    }
}

Я понял, что точка останова впервые попадает в эти методы жизненного цикла несколько раз, даже до того, как httpClient будет готов. Но после того, как httpClient будет готов, точка останова снова попадает в эти методы жизненного цикла. Таким образом, ваш код, который вы поместили внутрь, будет выполнен, если вы проверите

Это не настоящий обходной путь. auto render mode означает, что код может работать как на сервере, так и на клиенте. Различные службы зарегистрированы и доступны на каждой машине, особенно если выполняется предварительная отрисовка, и в этом случае возможностей нет. Документы объясняют этот точный сценарий в Вызов веб-API из ASP.NET Core Blazor

Panagiotis Kanavos 15.04.2024 15:12
Ответ принят как подходящий

По моему опыту, режим автоматического рендеринга требует, чтобы вы настроили службы одинаково как в клиентском, так и в серверном проекте (да, это дублируется). Это связано с тем, что в режиме автоматической визуализации ваши страницы изначально будут предварительно обработаны, что потребует регистрации служб в серверном проекте. Как только WASM вступит во владение, будут использоваться ваши сервисы, зарегистрированные в ваших клиентских проектах. Короче говоря, вам нужно настроить http-клиент в обоих проектах одинаково.

Ознакомьтесь с этим Документом Microsoft о настройке именованных Http-клиентов (это полезно, если вы настраиваете несколько Http-клиентов для внедрения зависимостей) и о том, как использовать IHttpClientFactory для создания именованных клиентов на лету.

Обновлено: Вот несколько примеров кода и пояснений.

Установить безымянный HttpClient в обоих проектах так же просто, как builder.Services.AddHttpClient();. Это сложно, поскольку вы не можете указать BaseAddress, используя эту настройку, поэтому каждый раз, когда вы отправляете HTTP-запрос от этого клиента, вы должны указывать полный URL-адрес конечной точки, к которой вы обращаетесь.

Чтобы использовать этот безымянный HttpClient, вам поможет следующий код в вашем компоненте.

[Inject] private IHttpClientFactory factory { get; set; } = default!;

private HttpClient client;

protected override Task OnInitializedAsync() {
    this.client = factory.CreateClient();
}

private async Task SomeMethodThatCallsAPI() {
    HttpResponseMessage response = await this.client.GetAsync("https://your.api.com/some/endpoint");
}

Я бы предложил настроить именованный клиент, даже если вы не думаете, что он вам нужен, потому что это позволяет вам настроить базовый адрес. Вот как это будет выглядеть.

Сначала ваша настройка (помните, оба проекта!)

builder.Services.AddHttpClient("MyAPI", client => {
    client.BaseAddress = new Uri("https://your.api.com/");
});

Тогда как вы будете использовать это в своем компоненте -

[Inject] private IHttpClientFactory factory { get; set; } = default!;

private HttpClient client;

protected override Task OnInitializedAsync() {
    this.client = factory.CreateClient("MyAPI");
}

private async Task SomeMethodThatCallsAPI() {
    HttpResponseMessage response = await this.client.GetAsync("some/endpoint");
}

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

Можете ли вы предоставить пример кода настройки службы http в обоих проектах так же, как служба с ограниченной областью действия? Мне не нужны несколько именованных Http-клиентов.

Robin Khan 15.04.2024 19:05

Отредактировал мой первоначальный ответ, добавив для вас несколько примеров и пояснений!

bg_smooove 15.04.2024 20:55

Другие вопросы по теме