C# 在异步方法中使用时不返回信号器调用

C# 在异步方法中使用时不返回信号器调用,c#,signalr,async-await,signalr.client,C#,Signalr,Async Await,Signalr.client,我不确定这是信号器问题还是异步/等待问题。当我的客户端应用程序(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(

我不确定这是信号器问题还是异步/等待问题。当我的客户端应用程序(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);
}
helper类中没有一个代码是异步的

第一个服务器调用(在
Initialise()
中)工作正常-它获取数据并将其传递给helper类。在调用它的
invoke
之前,这个过程不会出现问题-它被调用但不会返回,线程也不会经过这一行。我在服务器方法中放置了一个断点,可以确认它正在被调用并返回一个值,但由于某种原因,这不会返回到客户端

奇怪的是,如果我去掉
Initialise()
方法中的async/await关键字,一切都正常。我做错了什么?为什么这些关键字会影响helper类中的同步代码


(我意识到您通常不应该使用
async void
,但是由于Initialise()方法是“fire and forget”,我认为在这种情况下可以使用它)。

这一行导致UI线程死锁:

var moreData = _hubProxy.Invoke<BarData>("Method2").Result;
然后,等待
初始化中的
数据处理器.ProcessData

await _dataProcessor.ProcessData(data);
确保不要在其他任何地方使用
.Result
。等待

另一种解决方法是:

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);
}
public async void Initialise()
{
//从服务器获取数据-异步,因为它可能是长期运行的。
var data=await\u hubProxy.Invoke(“Method1”).ConfigureAwait(false);
_dataProcessor.ProcessData(数据);
}
注意
ConfigureAwait(false)
。在这种情况下,
wait
之后的继续操作将发生在非UI线程上。这将消除死锁,但这不是一个理想的解决方案,而是一种变通方法。此外,出于UI访问或某些线程安全考虑,您的逻辑可能需要在UI线程上继续


最好的解决方案是同时使用
configurewait(false)
(如果可能)和避免使用
.Result
.Wait
)进行阻塞。

谢谢您的回复。我不熟悉ConfigureAwait(),但本文以某种方式提供了问题的解释:。当我调试线程ID时,它显示UI线程正在调用
Initialise()
(如预期的那样),但另一个线程正在等待后执行帮助程序代码(这也是意料之中的。我想异步框架会启动一个新线程,在
wait
之后继续执行)。但我仍然不清楚为什么两个不同的线程之间会出现死锁?或者这与上下文有关,而不是与上面文章所描述的线程有关?@AndrewStephens,这是出乎意料的。如果您在WPF UI线程上调用
初始化
,而不调用
配置等待(false)
在任何地方,在
等待
之后都不应该有线程。框架不会神奇地衍生出新线程。你确定它是另一个线程吗?你是否使用
任务。在任何地方运行
所以你希望助手类代码(在
等待
完成后)在UI线程上运行,而不是在b/g线程上运行(这就是发生在我身上的情况)?我没有使用
任务。在任何地方运行
。我还尝试了
配置等待(false)
顺便说一句,但它没有帮助。谢谢你给了我一些东西。不幸的是,在我的真实代码中,helper类实际上是由许多独立的类组成的,第二个signer
invoke
位于嵌套方法中。如果不进行重构,使所有内容都异步可能是一个艰巨的任务!如果Initialise()不是异步的-我很好奇是什么导致了这个问题,以防以后我真的需要一些异步功能的时候它又回来了。我不认为
Initialize
是“fire and forget”。这意味着你的其余代码不关心是否(或是否)该对象已初始化。您可能会发现我在上的博客文章很有帮助。附议:您应该使用
async Task
而不是
async void
await _dataProcessor.ProcessData(data);
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);
}