简体   繁体   English

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

[英]Async call with await in HttpClient never returns

I have a call I am making from inside a xaml-based, C# metro application on the Win8 CP; 我正在Win8 CP上基于xaml的C# metro应用程序中进行调用; this call simply hits a web service and returns JSON data. 此调用只是命中一个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);

It hangs at the await but the http call actually returns almost immediately (confirmed through fiddler); 它挂起在awaithttp呼叫几乎立即返回(通过提琴手确认); it is as if the await is ignored and it just hangs there. 好像await被忽略了,它只是挂在那里。

Before you ask - YES - the Private Network capability is turned on. 在您询问之前 - 是 - 打开了专用网络功能。

Any ideas why this would hang? 任何想法为什么会挂起?

Check out this answer to my question which seems to be very similar. 查看我的问题的答案 ,这似乎非常相似。

Something to try: call ConfigureAwait(false) on the Task returned by GetStreamAsync() . 要尝试的东西:在GetStreamAsync()返回的Task上调用ConfigureAwait(false) GetStreamAsync() Eg 例如

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

Whether or not this is useful depends on how your code above is being called - in my case calling the async method using Task.GetAwaiter().GetResult() caused the code to hang. 这是否有用取决于你的代码是如何被调用的 - 在我的情况下使用Task.GetAwaiter().GetResult()调用async方法Task.GetAwaiter().GetResult()导致代码挂起。

This is because GetResult() blocks the current thread until the Task completes. 这是因为GetResult()阻止当前线程,直到任务完成。 When the task does complete it attempts to re-enter the thread context in which it was started but cannot because there is already a thread in that context, which is blocked by the call to GetResult() ... deadlock! 当任务完成时,它会尝试重新进入启动它的线程上下文,但不能,因为在该上下文中已经存在一个线程,该线程被GetResult()调用阻塞... 死锁!

This MSDN post goes into a bit of detail on how .NET synchronizes parallel threads - and the answer given to my own question gives some best practices. 这篇MSDN文章详细介绍了.NET如何同步并行线程 - 给出了我自己的问题的答案给出了一些最佳实践。

Just a heads up - if you miss the await at the top level in an ASP.NET controller, and you return the task instead of the result as a response, it actually just hangs in the nested await call(s) with no errors. 只是抬头 - 如果你错过了在ASP.NET控制器中的顶级等待,并且你返回任务而不是结果作为响应,它实际上只是在嵌套的await调用中挂起而没有错误。 A silly mistake, but had I seen this post it might have saved me some time checking through the code for something odd. 这是一个愚蠢的错误,但是如果我看到这篇文章,它可能会让我节省一些时间来查看代码中的奇怪内容。

Disclaimer: I don't like the ConfigureAwait() solution because I find it non-intuitive and hard to remember. 免责声明:我不喜欢ConfigureAwait()解决方案,因为我发现它不直观且难以记忆。 Instead I came to the conclusion to wrap non awaited method calls in Task.Run(() => myAsyncMethodNotUsingAwait()). 相反,我得出的结论是在Task.Run(()=> myAsyncMethodNotUsingAwait())中包装无休止的方法调用。 This seems to work 100% but might just be a race condition!? 这似乎100%工作,但可能只是一个竞争条件!? I'm not so sure what is going on to be honest. 我不太确定说实话是怎么回事。 This conclusion might be wrong and I risk my StackOverflow points here to hopefully learn from the comments :-P. 这个结论可能是错误的,我冒这个StackOverflow点的风险,希望从评论中学习:-P。 Please do read them! 请仔细阅读!

I just had the problem as described and found more info here . 我刚刚遇到了所描述的问题,并在此处找到了更多信息。

The statement is: "you can't call an asynchronous method" 声明是:“你不能调用异步方法”

await asyncmethod2()

from a method that blocks 来自阻止的方法

myAsyncMethod().Result

In my case I couldn't change the calling method and it wasn't async. 在我的情况下,我无法更改调用方法,它不是异步。 But I didn't actually care about the result. 但我实际上并不关心结果。 As I remember it also didn't work removing the .Result and have the await missing. 我记得它也没有工作删除.Result并等待失踪。

So I did this: 所以我这样做了:

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

In my case I didn't care about the result in the calling non-async method but I guess that is quite common in this use case. 在我的情况下,我不关心调用非异步方法的结果,但我想在这个用例中很常见。 You can use the result in the calling async method. 您可以在调用异步方法中使用结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM