Использование WebAPI в Blazor с аутентификацией - PullRequest
4 голосов
/ 05 октября 2019

Я использую базовый шаблон, который VS 2019 предоставляет с данными прогноза погоды при создании проекта ASP.NET WebAPI, и добавил некоторую базовую аутентификацию с логином пользователя и поддержкой токена JWT, который все прекрасно работает.

Я пытаюсь создать проект клиента Blazor, чтобы использовать API и отображать данные на странице. AFAIK Blazor не поддерживает локальное хранилище, поэтому я использую пакет Blazored LocalStorage, чтобы дать мне эту возможность. Моя проблема связана с тем фактом, что использование JS через OnInitializedAsync () невозможно в серверном блейзоре (https://github.com/aspnet/AspNetCore/issues/13396)), в результате я не уверен, каким образом предполагается использовать эти вызовы веб-API. Поскольку это приведет кисключение нулевой ссылки

protected override async Task OnInitializedAsync()
{
    var client = HttpFactory.CreateClient();
    var token = await LocalStorage.GetItemAsync<string>("authToken");
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
    var response = await client.GetAsync("url/WeatherForecast");
    var str = await response.Content.ReadAsStringAsync();
    Items = JsonConvert.DeserializeObject<IEnumerable<WeatherForecast>>(str);
}

Одним из предложений было использование метода OnAfterRenderAsync () для вызова их как JS, который был бы готов к тому времени. Какие полуработы, но, очевидно, пользовательский интерфейс не совпадают, потому что его нужно обновить- однако для ручного обновления кажется, что мне нужно вызвать StateHasChanged (), который, в свою очередь, снова вызывает метод OnAfterRender, и в результате я должен был поставить проверку, но это в конечном итоге кажется невероятно хакерским.

private bool hasRendered;
protected override async Task OnAfterRenderAsync(bool _)
{
    if (!hasRendered) return;
    var client = HttpFactory.CreateClient();
    var token = await LocalStorage.GetItemAsync<string>("authToken");
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
    var response = await client.GetAsync("https://url/WeatherForecast");
    var str = await response.Content.ReadAsStringAsync();
    Items = JsonConvert.DeserializeObject<IEnumerable<WeatherForecast>>(str);

    StateHasChanged();

    hasRendered = true;
}

Что такоеправильный способ использовать API с аутентификацией и корректно отображать данные на стороне клиента?

Дополнительный вопрос HttpClient не представляется инъецируемым на стороне сервера, и рекомендуется использовать HttpClientFactory - хорошо ли этоИдея создать клиента на каждый запрос или сделать синглтон и повторно использоватьклиентский проект?

1 Ответ

1 голос
/ 05 октября 2019

Q1

Одним из предложений было использование метода OnAfterRenderAsync () для вызова их, поскольку к этому времени JS будет готов. Какие полуработы, но, очевидно, пользовательский интерфейс не совпадает, потому что его нужно обновить - однако для обновления вручную, кажется, мне нужно вызвать StateHasChanged ();, который, в свою очередь, снова вызывает метод OnAfterRender , и в результате мне пришлось поставить чек, но это в конечном итоге кажется невероятно счастливым.

Все люди с той же проблемой, потому что это, в Методы жизненного цикла , новые OnAfterRenderAsync с firstRender parm задокументированы:

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    {
        await ... /// your auth code here.
    }
}

Q2

Дополнительный вопрос HttpClient hasnне кажется инъекционным на стороне сервера, и рекомендуется использовать HttpClientFactory - это хорошая идея, чтобы создать клиента при каждом запросе или создать одиночный файл и повторно использовать его во время проекта клиента?

Упрощение: я предлагаю вам создать две внешние библиотеки для ваших внутренних вызовов: одну, использующую запросы http (для модели, размещенной на Blazor Wasm), а другую просто вызывающую бэкэнд-функции c # (для сервера Blazor). Оба с общим интерфейсом для внутренних вызовов. Используйте DI, чтобы установить правильную библиотеку для каждой размещенной модели .

...