在HttpClient中使用await的异步调用永远不会返回

时间:2012-03-27 18:03:37

标签: c# asynchronous async-await dotnet-httpclient

我正在Win8 CP上基于xaml的C#城域应用程序内部进行调用;此调用只需访问Web服务并返回JSON数据。

HttpMessageHandler handler = new HttpClientHandler();

HttpClient httpClient = new HttpClient(handler);
httpClient.BaseAddress = new Uri("http://192.168.1.101/api/");

var result = await httpClient.GetStreamAsync("weeklyplan");
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(WeeklyPlanData[]));
return (WeeklyPlanData[])ser.ReadObject(result);

它挂在await http 调用几乎立即返回(通过fiddler确认);好像await被忽略了,只是挂在那里。

在您提出之前 - 是 - 已打开专用网络功能。

为什么会挂起来的任何想法?

3 个答案:

答案 0 :(得分:118)

查看this answer我的问题,看似非常相似。

要尝试的内容:在ConfigureAwait(false)返回的任务上调用GetStreamAsync()。 E.g。

var result = await httpClient.GetStreamAsync("weeklyplan")
                             .ConfigureAwait(continueOnCapturedContext:false);

这是否有用取决于上面代码的调用方式 - 在我的情况下使用async调用Task.GetAwaiter().GetResult()方法导致代码挂起。

这是因为GetResult()阻止当前线程,直到任务完成。当任务完成时,它会尝试重新进入启动它的线程上下文但不能,因为在该上下文中已经存在一个线程,该线程被GetResult()的调用阻止... 死锁!

This MSDN post详细介绍了.NET如何同步并行线程 - the answer given to my own question提供了一些最佳实践。

答案 1 :(得分:1)

请注意-如果您错过了ASP.NET控制器顶层的等待,并且返回了任务而不是结果作为响应,则它实际上只是挂在嵌套的等待调用中,没有错误。一个愚蠢的错误,但是如果我看过这篇文章,它可能节省了我一些时间来检查代码中是否有奇怪的事情。

答案 2 :(得分:0)

免责声明:我不喜欢ConfigureAwait()解决方案,因为我发现它不直观且难以记住。相反,我得出结论,将未等待的方法调用包装在Task.Run(()=> myAsyncMethodNotUsingAwait())中。这似乎可以100%起作用,但可能只是比赛条件!?我不太确定这是怎么回事。这个结论可能是错误的,我冒着我在此处的StackOverflow风险,希望从评论中学习:-P。请务必阅读它们!

我只是遇到了上述问题,并找到了更多信息here

该语句是:“您不能调用异步方法”

await asyncmethod2()

通过阻止的方法

myAsyncMethod().Result

就我而言,我无法更改调用方法,并且它不是异步的。但是我实际上并不关心结果。我记得它也无法删除.Result并失去等待。

所以我做到了:

public void Configure()
{
    var data = "my data";
    Task.Run(() => NotifyApi(data));
}

private async Task NotifyApi(bool data)
{
    var toSend = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json");
    await client.PostAsync("http://...", data);
}

就我而言,我并不在乎调用非异步方法的结果,但我想在这种用例中这很普遍。您可以在调用异步方法中使用结果。