[英]Why do HTTP requests never return with async await?
我正在尝试从在IIS 8.5上运行的ASP.NET应用程序内对另一个服务器进行HTTP调用。
首先,我从Microsoft的文章“ 从.NET客户端(C#)调用Web API”中获取了一些提示。 我可以很容易地看到它们在此处进行HTTP调用的方式。 仅显示一个简化的示例:
static async Task<Product> GetProductAsync(string path)
{
HttpResponseMessage response = await client.GetAsync(path);
if (response.IsSuccessStatusCode)
{
// retrieve response payload
... = await response.Content.ReadAsAsync<...>();
}
// do something with data
}
我想这很容易,所以我很快为我的应用程序编写了一个类似的方法(请注意, ReadAsAsync
扩展方法似乎需要一个附加的库 ,因此我选择了一种内置的,更抽象的方法,但推测是类似的方法):
private async Task<MyInfo> RetrieveMyInfoAsync(String url)
{
var response = await HttpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
var responseBody = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<MyInfo>(responseBody);
}
不幸的是,调用此方法将导致我的应用程序挂起。 调试时,事实证明,对GetAsync
的await
调用永远不会返回。
在四处搜寻之后,我偶然发现了一个遥远相似的问题 ,在其评论部分中,我发现了 B先生的 一个非常有趣的建议 :
删除所有异步内容,并确保其有效。
因此,我尝试了一下:
private Task<MyInfo> RetrieveMyInfoAsync(String url)
{
return HttpClient.GetAsync(url).ContinueWith(response =>
{
response.Result.EnsureSuccessStatusCode();
return response.Result.Content.ReadAsStringAsync();
}).ContinueWith(str => JsonConvert.DeserializeObject<MyInfo>(str.Result.Result));
}
(对我而言)有些令人惊讶,它有效。 GetAsync
在不到一秒钟的时间内从其他服务器返回了预期的响应。
现在,同时使用AngularJS,我对诸如response.Result.Content
和str.Result.Result
类的东西感到有些失望。 在AngularJS中,我希望上面的调用就像这样:
$http.get(url).then(function (response) {
return response.data;
});
即使我们不赞成JavaScript中发生的自动JSON反序列化,但AngularJS代码仍然更容易,例如, response
未包装在promise中或类似的内容,我也不会得到Task<Task<...>>
这样的结构Task<Task<...>>
从延续函数中返回另一个诺言时。
因此,如果后者可以正常工作的话,我对使用ContinuesWith
语法而不是更具可读性的async-await模式并不满意。
我的C#HTTP调用的async-await变体在做什么?
因此,从ConfigureAwait(false)
帮助解决您的问题这一事实来看,请阅读Stephen Cleary的博客中的内容: http : //blog.stephencleary.com/2012/07/dont-block-on-async-code.html
这个家伙几乎是一个async
专家(他写了《 C#Cookbook中的并发性》一书),所以我能说的他可能解释得更好。 基本上,您是在某个地方阻塞ASP.NET线程,也许不是一直使用await
而是而是Wait
, Result
或GetResult()
。 您应该可以使用该博客自己诊断问题。
ConfigureAwait(false)
作用是不会捕获当前上下文,因此HTTP请求在ASP.NET上下文以外的其他位置(正确)执行,从而避免了死锁。
编辑:
根据您的评论判断, GetAwaiter().GetResult()
是导致此问题的原因。 如果将其更改为await
,并将调用方法更改为async
,则可能会修复所有问题。
由于C#7.0和async Task Main()
方法都支持,所以实际上没有理由阻塞而不是在应用程序代码中使用await
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.