Blazor HttpClient застрял в GetAsync

Я провожу тест в приложении Blazor на стороне клиента, ориентированном на Blazor 3.0.0-preview4-19216-03

Страница бритвы:

@page "/counter"
@using BlazorServiceTest
@inject IWebCrawlServiceAsync WebCrawler

<h1>Counter</h1>

<p>Current count: @debug</p>

<button class="btn btn-primary" onclick="@IncrementCount">Click me</button>

@functions {
    string debug = "";

    async void IncrementCount()
    {
        debug = await WebCrawler.GetWeb();
    }
}

Внедрение зависимости:

using BlazorServiceTest;
using Microsoft.AspNetCore.Components.Builder;
using Microsoft.Extensions.DependencyInjection;

namespace BlazorServicesTest
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {   
            services.AddSingleton<IWebCrawlServiceAsync, WebCrawlServiceAsync>();            
        }

        public void Configure(IComponentsApplicationBuilder app)
        {
            app.AddComponent<App>("app");
        }
    }
}

Обслуживание:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;

namespace BlazorServiceTest
{
    public interface IWebCrawlServiceAsync
    {
        Task<string> GetWeb();
    }

    public class WebCrawlServiceAsync : IWebCrawlServiceAsync
    {
        private HttpClient _client;    

        public WebCrawlServiceAsync(HttpClient client)
        {
            _client = client;
        }

        public async Task<string> GetWeb()
        {
            var response = await _client.GetAsync("https://postman-echo.com/response-headers?foo1=bar1&foo2=bar2");
            var result = await response.Content.ReadAsStringAsync();
            return result;
        }
    }
}

Каждый раз, когда я нажимаю кнопку «Счетчик увеличения», ничего не происходит, и вызов службы GetWeb застревает в вызове GetAsync.

ОБНОВИТЬ

Если я отлаживаю службу WebCrawler в отладчике Chrome WASM, он запрашивает

введите описание изображения здесь

Но раздел ответа пуст:

введите описание изображения здесь


person Fritjof Berggren    schedule 02.05.2019    source источник
comment
Куда вы добавляете HttpClient? Или это добавляется автоматически?   -  person Nkosi    schedule 02.05.2019
comment
Он внедрен Blazor и настроен для работы в среде WASM. Я сам создал новый экземпляр HttpClient и тоже не работал.   -  person Fritjof Berggren    schedule 02.05.2019
comment
Я подозреваю, что это как-то связано с async void. Я читаю больше, чтобы быть уверенным /   -  person Nkosi    schedule 02.05.2019


Ответы (3)


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

Чтобы убедиться, что это ваша проблема, вы можете попробовать https://postman-echo.com/response-headers?foo1=bar1&access-control-allow-origin=*, это может сработать.

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

Таким образом, клиентская часть Blazor - не самая лучшая платформа для веб-краулера. То же самое касается любого приложения на JS или WASM.

На стороне сервера Blazor проблем быть не должно. Или используйте службу веб-API.


Вы можете попробовать это в приложении Wasm:

@page "/"
@inject HttpClient Http

<h1>Hello, world!</h1>
<div>
    <button class="btn btn-primary" @onclick="GetData1">With CORS</button>
    <button class="btn btn-primary" @onclick="GetData2">No CORS</button>
</div>
<div>@json</div>

@code
{
    string json = ".";

    async Task GetData1()
    {        
        json = await Http.GetStringAsync(
         "https://postman-echo.com/response-headers" + 
         "?foo1=bar1&access-control-allow-origin=*");
    }

    async Task GetData2()
    {
        json = "Getting w/o CORS... ";
        json = await Http.GetStringAsync(
          "https://postman-echo.com/response-headers?foo1=bar1");
    }
}
person Henk Holterman    schedule 02.05.2019
comment
Это была проблема CORS, использование этого URL-адреса с 'access-control-allow-origin = *' сделало свою работу. Собираюсь протестировать Blazor Serverside, так как он выглядит более робастным. Спасибо за ответы! - person Fritjof Berggren; 03.05.2019
comment
Ах да, как он работал? Пожалуйста, просветите нас. 'access-control-allow-origin = *' в приведенном выше URL-адресе - это не что иное, как параметр строки запроса, который может быть повторен, как и два других параметра. Просто поместите этот URL-адрес в адресную строку браузера и нажмите Enter, чтобы увидеть возвращенный json. Вы можете легко заменить последний параметр на это: 'allow-origin = *' - person enet; 03.05.2019
comment
Кстати, вам, безусловно, следует изучить и протестировать серверный Blazor, но это не имеет никакого отношения к проблеме. Как я уже сказал, проблема не в Blazor или HttpClient. - person enet; 03.05.2019
comment
@Henk Holterman, что это: 'access-control-allow-origin = *' Что вы пытаетесь здесь сделать;) access-control-allow-origin - это заголовок ответа, предоставленный сервером - person enet; 03.05.2019
comment
@Issac, посмотрите URL и прочтите там документацию. Это специальный сайт для тестирования API. - person Henk Holterman; 03.05.2019
comment
Так ? Не могли бы вы рассказать мне, что вы получаете, помещая 'access-control-allow-origin = *' в URL ... Вы пишете: Чтобы проверить, вы можете попробовать ..... Что дает добавление еще одного параметр можно сделать. Было два параметра: foo1 и foo2; теперь вы вводите (или меняете) новый параметр; это все. Вы понимаете, что «разрешение-контроль-доступ-происхождение»? - person enet; 03.05.2019
comment
Вы все еще не читали документы на postman-echo.com. Вы хотя бы заметили часть URL-адреса / response-headers? - person Henk Holterman; 03.05.2019
comment
Хорошо, @ Хенк Холтерман. Я отвечу вам, и я ожидаю, что вы ответите мне. Нет, я не читал. Зачем мне это читать. Да, я заметил часть URL-адреса / response-headers, ну и что. Еще заметил, что ваши ответы короткие и, извините, уклончивые. Теперь вы можете ответить на вопрос сверху: Не могли бы вы рассказать мне, что вы получаете, помещая 'access-control-allow-origin = *' в URL ... Вы пишете: Чтобы проверить, вы можете попробовать. .... Что может сделать добавление еще одного параметра. - person enet; 03.05.2019
comment
Как засвидетельствовал этрагу, сделал свою работу. Почему бы тебе просто не попробовать? Сообщение - mcve. - person Henk Holterman; 03.05.2019
comment
Позвольте нам продолжить это обсуждение в чате. - person enet; 03.05.2019
comment
Нет, я не болтаю. И обсуждение, насколько мне известно, закрыто. - person Henk Holterman; 03.05.2019

Я подозреваю, что это как-то связано с async void.

Вам нужно, чтобы обработчик возвращал Task, а не void

Например

@page "/counter"
@using BlazorServiceTest
@inject IWebCrawlServiceAsync WebCrawler

<h1>Counter</h1>

<p>Current count: @debug</p>

<button class="btn btn-primary" onclick="@IncrementCount">Click me</button>

@functions {
    string debug { get; set; } = "";

    async Task IncrementCount() { //<-- Note Change here
        debug = await WebCrawler.GetWeb();
    }
}

поддержка асинхронного обработчика событий доступна во фреймворке

Ссылка Проблема GitHub: вызов асинхронной функции с помощью onclick

person Nkosi    schedule 02.05.2019
comment
Привет, Nkosi, спасибо за ответ, но, к сожалению, это не сработало, я добавил частную асинхронную задачу IncrementCount (), но без разницы. - person Fritjof Berggren; 02.05.2019
comment
@Nkosi, вы можете использовать async void с событиями. Я не уверен, что this.StateHasChanged (); вызов необходим, так как этот метод всегда автоматически вызывается после возникновения события. - person enet; 02.05.2019
comment
Blazor поддерживает async Task для событий, что очень предпочтительно. Когда вы действительно используете async void, также завершите StateHasChanged (), потому что фреймворк этого не сделает (не может). - person Henk Holterman; 19.05.2021

Это может быть связано с проблемой конфигурации CORS на сервере, которую вы не можете контролировать. Я считаю, что эта проблема не имеет ничего общего с Blazor. Чтобы проверить это, определите локальный файл json в своем приложении и получите к нему доступ с помощью того же кода, который вы используете в своем приложении.

Надеюсь, это сработает ...

ОБНОВЛЕНИЕ

Я не совсем уверен, что запрос не выполняется из-за проблемы с конфигурацией CORS, по крайней мере, не исключительно. Мне кажется, что это тоже связано с SSL / TLS. Это сообщение об ошибке было выдано Fiddler:

fiddler.network.https> Не удалось установить соединение HTTPS. System.IO.IOException Невозможно прочитать данные из транспортного соединения: существующее соединение было принудительно закрыто удаленным узлом. ‹Существующее соединение было принудительно закрыто удаленным хостом

Базовое соединение закрыто, и для безопасного канала SSL / TLS невозможно установить доверительные отношения.

Думаю, я опубликую этот вопрос в github, чтобы лучше понять, что здесь пошло не так.

person enet    schedule 02.05.2019
comment
По словам @etragu, он внедрен Blazor и настроен так, чтобы он работал в среде WASM. Простите, без разницы ... Код раньше не замечал ... - person enet; 02.05.2019