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

kei*_*en7 88 c# asynchronous async-await dotnet-httpclient

我正在C#Win8 CP上基于xaml的metro应用程序内部进行调用; 此调用只是命中一个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);
Run Code Online (Sandbox Code Playgroud)

它挂起,awaithttp呼叫几乎立即返回(通过提琴手确认); 就好像await被忽略了它只是挂在那里.

在您询问之前 - 是 - 打开了专用网络功能.

任何想法为什么会挂起?

Ben*_*Fox 123

查看我的问题的答案,这似乎非常相似.

要尝试的东西:调用ConfigureAwait(false)返回的任务GetStreamAsync().例如

var result = await httpClient.GetStreamAsync("weeklyplan")
                             .ConfigureAwait(continueOnCapturedContext:false);
Run Code Online (Sandbox Code Playgroud)

这是否有用取决于你的代码是如何被调用的 - 在我的情况下调用async方法Task.GetAwaiter().GetResult()使得代码挂起.

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

这篇MSDN文章详细介绍了.NET如何同步并行线程 - 给出了我自己的问题的答案给出了一些最佳实践.

  • 谢谢,在看到之前几乎放弃了async/await. (8认同)
  • 我也是!为什么这些东西没有更好的记录?再次感谢 (4认同)
  • 如果它不在 UI 上下文和 ASP.NET 上下文中,它会发生吗? (2认同)
  • 很棒的答案!但是我很困惑为什么到目前为止我在使用 HttpClient 时只有这个问题,看起来 HttpClient 中的底层实现没有正确实现。我发现的其他解决方法涉及将当前线程设置为 STA,这有帮助,但实际上是间接的,尤其是当您使用 3rd 方程序集并且不知道在幕后某些调用肯定会等待它的响应永远不会得到。在我的情况下,dll 是内部的,所以我们能够配置等待......但它必须在 HttpClient obj 的最低级别上完成。 (2认同)
  • @ChrisSchaller确保在http://stackoverflow.com/a/10351400/174735上阅读完整的答案,这完全解释了这个问题. (2认同)

boz*_*zle 5

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