我正在尝试在运行于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
扩展方法似乎需要一个额外的库 (链接),因此我选择了其中一个内置的、更抽象但可能类似的方法):
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
调用从未返回。
搜索了一下,我偶然发现一个类似的问题,在其评论部分中,我找到了Mr. 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或类似的东西,也不会在继续函数中返回另一个promise时出现像Task<Task<...>>
这样的结构。因此,如果后者正常工作,我不太喜欢使用这个
ContinuesWith
语法而不是更易读的async-await模式。在我的C# HTTP调用的async-await变体中,我做错了什么?
await HttpClient.GetAsync(url).ConfigureAwait(false)
,并告诉我是否有帮助。 - V0ldekWait()
、Result
或者GetResult()
? - FCinGetAwaiter().GetResult()
导致了死锁。请查看我的答案以获得更好的解释。 - V0ldek