【发布时间】:2019-01-16 19:23:52
【问题描述】:
我正在尝试从在 IIS 8.5 上运行的 ASP.NET 应用程序中对另一台服务器进行 HTTP 调用。
首先,我从 Microsoft 的一篇文章中获得了一些提示,Call a Web API From a .NET Client (C#)。 我可以很容易地看到他们如何在那里进行 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 扩展方法appears to require an additional library,所以我选择了一个内置的、更抽象的,但在其他方面可能类似的方法):
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);
}
不幸的是,调用此方法会导致我的应用程序挂起。调试时发现await 对GetAsync 的调用永远不会返回。
搜索了一下,我偶然发现了一个remotely similar issue,在其cmets部分我找到了a very interesting suggestionMr. 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 或类似的东西中,当从 continuation 函数中返回另一个 Promise 时,我也不会最终得到像 Task<Task<...>> 这样的结构。
因此,我对不得不使用 ContinuesWith 语法而不是更易读的 async-await 模式(如果后者能正常工作的话)感到不满意。
我在 C# HTTP 调用的 async-await 变体中做错了什么?
【问题讨论】:
-
试试
await HttpClient.GetAsync(url).ConfigureAwait(false)看看是否有帮助。 -
您是否在任何地方使用
Wait()、Result或GetResult()? -
@V0ldek:确实,这很有帮助。那里发生了什么?
-
这是 Stephen Cleary 的一个很好的解释:stackoverflow.com/questions/13489065/…
-
@FCin:在我的请求之前的调用堆栈中,除了一些
await调用之外,我正在使用WhenAll和GetAwaiter().GetResult(),是的。
标签: c# asp.net asynchronous async-await task-parallel-library