在异步方法中使用时,SignalR不会返回

时间:2014-03-20 09:34:11

标签: c# signalr async-await signalr.client

我不确定这是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>

1 个答案:

答案 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进行屏蔽。