【问题标题】:Async Http Request from component in Blazor来自 Blazor 中组件的异步 Http 请求
【发布时间】:2020-06-12 09:26:22
【问题描述】:

我在 Blazor 中创建了一个组件列表,这些组件中的每一个都需要从网页请求一些数据。该列表在 .razor 页面上创建如下:

@foreach(stringcomp in Complist){
   <myComponent />
}

创建了大约 100 个组件。在所有这些组件上,都会执行以下 URL 请求(使用此代码):

        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            if (firstRender)
            {
                await GetUrl("some url here");
            }
        }


        public async Task<string> GetUrl(string url)
        {
            HttpClient client = new HttpClient();
            var request = new HttpRequestMessage(HttpMethod.Get, url);
            request.Headers.Add("User-Agent", "get data service");
            var response = await client.SendAsync(request).ConfigureAwait(false);
            string res = null;
            if (response.IsSuccessStatusCode)
            {
                using var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
                var streamReader = new StreamReader(responseStream);
                res = await streamReader.ReadToEndAsync().ConfigureAwait(false);
            }
            return res;
        }

这样做我遇到了一些问题,我对 SendAsync 的大多数调用都不会返回值。我已经明白这是因为锁定状态,但我一生都无法弄清楚如何解决它。最相似的答案建议设置 .ConfigureAwait(false) 但这并没有在我的情况下产生不同的结果。

所以我的问题是:我可以在不同的组件中同时请求网页,并确保它们不会挂起/查找。由于有许多请求有时需要很长时间(5-10 秒)才能完成,因此同步执行它们并不是一种替代方法。

可能还需要提到我的代码和页面是分开的,每个 .razor 页面都使用@inherits 来获取其功能/逻辑

【问题讨论】:

  • 您是否有理由根据 &lt;myComponent&gt; 发出请求,而不是通过单个 http 请求获取您需要显示的所有数据?
  • 总共有超过 500 个请求,有些请求很慢,如果我需要在显示数据之前等待我的数据,等待时间可能会很长。另一种方法是在父母中做所有事情并在收到数据时将数据传递给孩子,但为什么需要这样做呢?我不明白为什么我的方法不起作用,因为在不同组件中执行单独的请求应该可以正常工作(即使我的情况有些极端)
  • 浏览器通常限制为 5 个并行请求(移动设备上为 2 个),并且 Blazor 还不是真正的多线程,这可以解释您的问题

标签: async-await blazor dotnet-httpclient blazor-server-side


【解决方案1】:

尝试如下使用IHttpClientFactory:

[Inject] public IHttpClientFactory clientFactory { get; set;}
using System.IO;

您的 GetUrl 方法:

 public async Task<string> GetUrl(string url)
{
    var request = new HttpRequestMessage(HttpMethod.Get, url);
    request.Headers.Add("Accept", "application/json");
    request.Headers.Add("User-Agent", "get data service");


    var client = clientFactory.CreateClient();

    var response = await client.SendAsync(request);

    string res = null;

    if (response.IsSuccessStatusCode)
    {
        using var responseStream = await response.Content.ReadAsStreamAsync();
        var streamReader = new StreamReader(responseStream);
        res = await streamReader.ReadToEndAsync().ConfigureAwait(false);
    }

    return res;
}

Startup.cs

 public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpClient();

    // More code here...
 }

希望这行得通...

【讨论】:

  • @inject IHttpClientFactory clientFactory 仅适用于 .razor 页面,但我的代码在 .cs 内辞职。我的 .razor 页面继承了 .cs。
  • 将此属性添加到您的类后面: [Inject] public IHttpClientFactory clientFactory { get;设置;}
  • 试过你的代码,不幸的是问题仍然存在,一些 SendAsync 调用永远不会返回(可能是死锁)
  • 你想做什么?为什么必须实例化 100 个组件并将它们存储在列表中?
  • 每个组件代表一个不同的网页,每个组件都假设获取有关自己页面的信息(这就是每个组件都有自己的请求的原因)并显示它。问题是只有少数 SendAsync 调用确实返回,大多数都被卡住并且永远不会返回任何内容。注意:由于列表项是在循环中创建的,因此几乎同时发送所有请求。
猜你喜欢
  • 1970-01-01
  • 2021-03-17
  • 2020-10-25
  • 1970-01-01
  • 1970-01-01
  • 2012-04-03
  • 1970-01-01
  • 2022-11-28
  • 1970-01-01
相关资源
最近更新 更多