我不确定这是SignalR问题还是async / await问题。当我的客户端应用程序(WPF)启动时,它会进行一些初始化: -
public async void Initialise()
{
// Get data from the server - async, as it may be long-running.
var data = await _hubProxy.Invoke<FooData>("Method1");
_dataProcessor.ProcessData(data);
}
_dataProcessor
是一个辅助类,它使用传递给它的数据执行某些操作,然后在某些时候使用类似于以下行的方法调用不同的服务器方法: -
var moreData = _hubProxy.Invoke<BarData>("Method2").Result;
帮助程序类中的所有代码都不是异步的。
第一个服务器调用(在Initialise()
中)工作正常 - 它获取数据并将其传递给帮助程序类。这一过程没有问题,直到它的 invoke
- 它被调用但永远不会返回,并且线程永远不会超过这一行。我在服务器方法中设置了一个断点,可以确认它正在被调用并返回一个值,但由于某种原因,这并没有回到客户端。
奇怪的是,如果我在Initialise()
方法中取出async / await关键字,一切正常。我究竟做错了什么?为什么这些关键字会影响帮助程序类中的同步代码?
(我意识到你通常不应该使用async void
,但是由于Initialise()方法是&#34;激发并忘记&#34;,我认为在这种情况下它是可以的。)< / p>
答案 0 :(得分:4)
此行导致UI线程出现死锁:
var moreData = _hubProxy.Invoke<BarData>("Method2").Result;
使ProcessData
成为async
方法并等待其中的_hubProxy.Invoke
:
var moreData = await _hubProxy.Invoke<BarData>("Method2");
然后,等待_dataProcessor.ProcessData
中的Initialise
:
await _dataProcessor.ProcessData(data);
请确保您不在其他地方使用.Result
或.Wait
。
另一种解决方法就是:
public async void Initialise()
{
// Get data from the server - async, as it may be long-running.
var data = await _hubProxy.Invoke<FooData>("Method1").ConfigureAwait(false);
_dataProcessor.ProcessData(data);
}
注意ConfigureAwait(false)
。在这种情况下,await
之后的延续将在非UI线程上发生。这将消除死锁,但这不是一个理想的解决方案,而是一种解决方法。此外,您的逻辑可能需要UI线程的延续,UI访问或一些线程安全问题。
最佳解决方案是同时使用ConfigureAwait(false)
(如果可能)并避免使用.Result
或.Wait
进行屏蔽。