110

我从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);

它挂在awaithttp调用实际上几乎立即返回(通过提琴手确认);就好像await被忽略了,它只是挂在那里。

在您询问之前- 是的 - 专用网络功能已打开。

任何想法为什么这会挂起?

4

3 回答 3

162

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

可以尝试的方法:调用ConfigureAwait(false)返回的任务GetStreamAsync()。例如

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

这是否有用取决于上面的代码是如何被调用的——在我的例子中,调用async方法 usingTask.GetAwaiter().GetResult()会导致代码挂起。

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

这篇 MSDN 帖子详细介绍了 .NET 如何同步并行线程 -对我自己的问题的回答提供了一些最佳实践。

于 2012-04-29T02:39:17.337 回答
8

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

于 2019-07-04T04:22:10.277 回答
0

免责声明:我不喜欢 ConfigureAwait() 解决方案,因为我发现它不直观且难以记忆。相反,我得出的结论是在 Task.Run(() => myAsyncMethodNotUsingAwait()) 中包装非等待的方法调用。这似乎 100% 有效,但可能只是竞争条件!?老实说,我不太确定发生了什么。这个结论可能是错误的,我在这里冒着我的 StackOverflow 点的风险希望从评论中学习:-P。请务必阅读它们!

我刚刚遇到了所描述的问题,并在此处找到了更多信息。

声明是:“你不能调用异步方法”

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);
}

就我而言,我并不关心调用非异步方法的结果,但我想这在这个用例中很常见。您可以在调用异步方法中使用结果。

于 2019-04-02T08:46:38.277 回答