使用await关键字时,.NET HttpClient挂起
本文关键字:NET HttpClient 挂起 await 关键字 使用 | 更新日期: 2023-09-27 18:23:42
考虑到这个有趣的答案后,HttpClient.GetAsync(…)永远不会返回。。。,当我使用wait时,我的HttpClient仍然没有返回(下面的示例代码)。此外我使用asp.net MVC5控制器(UI驱动)和WebApi中的这个助手例程。我能做些什么:
- 用wait代替(可怕的)。结果还有这个函数返回吗
- 从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
所有内容。仅仅在其中一个上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
进行一次阻塞调用就足以死锁。您需要"一路异步"。