使用await关键字时,.NET HttpClient挂起

本文关键字:NET HttpClient 挂起 await 关键字 使用 | 更新日期: 2023-09-27 18:23:42

考虑到这个有趣的答案后,HttpClient.GetAsync(…)永远不会返回。。。,当我使用wait时,我的HttpClient仍然没有返回(下面的示例代码)。此外我使用asp.net MVC5控制器(UI驱动)和WebApi中的这个助手例程。我能做些什么:

  1. 用wait代替(可怕的)。结果还有这个函数返回吗
  2. 从MVC控制器和WebApi重复使用这个相同的例程

显然,我应该用.ConfigureAwait(false)替换.Result,但这似乎与上面引用的帖子中的"Task4"在等待httpClient.GetAsync时工作得很好的事实相矛盾。或者,我需要针对Controller和WebApi情况单独使用例程吗?

public static async Task<IEnumerable<TcMarketUserFullV1>> TcSearchMultiUsersAsync(string elasticQuery)
{
    if (string.IsNullOrEmpty(elasticQuery)) return null;
    IEnumerable<TcMarketUserFullV1> res = null;
    using (var hclient = new HttpClient())
    {
        hclient.BaseAddress = new Uri("https://addr.servicex.com");
        hclient.DefaultRequestHeaders.Accept.Clear();
        hclient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        hclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",
            CloudConfigurationManager.GetSetting("jwt-bearer-token"));
        // Why does this never return when await is used?
        HttpResponseMessage response =  hclient.GetAsync("api/v2/users?q=" + elasticQuery + "&search_engine=v2").Result; 
        if (response.IsSuccessStatusCode)
        {
            var content = await response.Content.ReadAsStringAsync();
            res = JsonConvert.DeserializeObject<TcMarketUserFullV1[]>(content).AsEnumerable();
        }
        else{log.Warn("...");}
    } 
    return res;
} 

更新:我的调用链,它从Telerik Kendo Mvc开始。网格数据绑定调用如下:

[HttpPost]
public async Task<ActionResult> TopLicenseGrid_Read([DataSourceRequest]DataSourceRequest request)
{
    var res = await GetLicenseInfo();
    return Json(res.ToDataSourceResult(request)); // Kendo.Mvc.Extensions.DataSourceRequest
}

然后:

private async Task<IEnumerable<CsoPortalLicenseInfoModel>> GetLicenseInfo()
{
  ...
  // Never returns
  var qry = @"app_metadata.tc_app_user.country:""DE""";
  return await TcSearchMultiUsersAsync(qry);
}

然后,上面完整显示的例程,但现在没有。结果:

public static async Task<IEnumerable<TcMarketUserFullV1>> TcSearchMultiUsersAsync(string elasticQuery)
{
    if (string.IsNullOrEmpty(elasticQuery)) return null;
    IEnumerable<TcMarketUserFullV1> res = null;
    using (var hclient = new HttpClient())
    {
        hclient.BaseAddress = new Uri("https://addr.servicex.com");
        hclient.DefaultRequestHeaders.Accept.Clear();
        hclient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        hclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",
            CloudConfigurationManager.GetSetting("jwt-bearer-token"));
        // This now returns fine
        HttpResponseMessage response =  hclient.GetAsync("api/v2/users?search_engine=v2&q=" + elasticQuery"); 
        if (response.IsSuccessStatusCode)
        {
            // This returns my results fine too
            var content = await response.Content.ReadAsStringAsync();
            // The following line never returns results. When debugging, everything flows perfectly until I reach the following line, which never 
            // returns and the debugger returns me immediately to the top level HttpPost with a result of null. 
            res = JsonConvert.DeserializeObject<TcMarketUserFullV1[]>(content).AsEnumerable();
        }
        else{log.Warn("...");}
    } 
    return res;
} 

使用await关键字时,.NET HttpClient挂起

您需要await所有内容。仅仅在其中一个上await是不够的,你需要在所有这些上await

此:

HttpResponseMessage response = hclient.GetAsync(
                        "api/v2/users?q=" + elasticQuery + "&search_engine=v2").Result;

应为:

HttpResponseMessage response = await hclient.GetAsync(
                                "api/v2/users?q=" + elasticQuery + "&search_engine=v2");

只要对.Result进行一次阻塞调用就足以死锁。您需要"一路异步"