WebClient.DownloadStringTaskAsync 没有等待就无法工作
WebClient.DownloadStringTaskAsync doesn't work without await
我有一个带有一个按钮和一个文本块的简单 wpf 应用程序。按钮单击事件处理程序 运行 下一个代码:
var resultTask = webClient.DownloadStringTaskAsync("http://google.com");
textBlock.Text = resultTask.Result;
在我使用 await
之前这不起作用(它是环聊)
var result = await ebClient.DownloadStringTaskAsync("http://google.com");
textBlock.Text = result;
但在简单的控制台应用程序中它工作正常。
var resultTask = webClient.DownloadStringTaskAsync("http://google.com");
Console.WriteLine(resultTask.Result);
你能解释一下为什么第一个变体在 wpf 中不起作用吗?
您似乎在 UI 事件线程上陷入僵局。以下问题的公认答案对其进行了更详细的解释:
这是同步上下文的常见问题;基本上,.Result
在 UI 线程可用之前无法获取同步上下文,并且 UI 线程在 .Result
完成(或失败)之前不可用.基本上,你自己陷入了僵局,这就是为什么你不应该使用 .Wait()
或 .Result
除非你知道同步上下文是安全的 - 只是 await
.
它在控制台应用程序中工作,因为没有同步上下文:可以在池线程上将延续标记为完成。在 WPF 中,同步上下文将工作推送到 UI 线程,由于死锁,这是无法做到的。
一个 hacky 修复是在 *Async
方法之后添加 .ConfigureAwait(false)
:
var resultTask = webClient.DownloadStringTaskAsync("http://google.com")
.ConfigureAwait(false);
但这出于所有错误的原因而起作用,应该避免。要么使用 await
,要么使用同步调用。不要这样做 "sync over async" - 这是一个非常糟糕的主意。
我有一个带有一个按钮和一个文本块的简单 wpf 应用程序。按钮单击事件处理程序 运行 下一个代码:
var resultTask = webClient.DownloadStringTaskAsync("http://google.com");
textBlock.Text = resultTask.Result;
在我使用 await
之前这不起作用(它是环聊)var result = await ebClient.DownloadStringTaskAsync("http://google.com");
textBlock.Text = result;
但在简单的控制台应用程序中它工作正常。
var resultTask = webClient.DownloadStringTaskAsync("http://google.com");
Console.WriteLine(resultTask.Result);
你能解释一下为什么第一个变体在 wpf 中不起作用吗?
您似乎在 UI 事件线程上陷入僵局。以下问题的公认答案对其进行了更详细的解释:
这是同步上下文的常见问题;基本上,.Result
在 UI 线程可用之前无法获取同步上下文,并且 UI 线程在 .Result
完成(或失败)之前不可用.基本上,你自己陷入了僵局,这就是为什么你不应该使用 .Wait()
或 .Result
除非你知道同步上下文是安全的 - 只是 await
.
它在控制台应用程序中工作,因为没有同步上下文:可以在池线程上将延续标记为完成。在 WPF 中,同步上下文将工作推送到 UI 线程,由于死锁,这是无法做到的。
一个 hacky 修复是在 *Async
方法之后添加 .ConfigureAwait(false)
:
var resultTask = webClient.DownloadStringTaskAsync("http://google.com")
.ConfigureAwait(false);
但这出于所有错误的原因而起作用,应该避免。要么使用 await
,要么使用同步调用。不要这样做 "sync over async" - 这是一个非常糟糕的主意。