SignalR等待结果

时间:2013-01-29 16:14:58

标签: multithreading web-services task signalr wait

尝试将消息推送到UI并接收一些结果,以便从Web服务以同步方式返回。 方法代码如下。

[OperationContract]
public string DecypherCaptcha(string captcha)
{
    var connection = new HubConnection("http://localhost:51806");
    IHubProxy hub = connection.CreateHubProxy("robo");

    string decaptcha = null;
    hub.On("captchaDecyphered", decyphered =>
    {
        decaptcha = decyphered;
    });

    connection.Start().Wait();
    hub.Invoke<string>("DecypherCaptcha", new object[] { captcha });

    return decaptcha;
}

问题是该方法在从hub captchaDecyphered获取值之前完成。但是,方法退出后,表达式{ decaptcha = decyphered; }会从服务器触发 为其添加ManualResetEvent标志和WaitOne()并不能解决冻结执行和阻止hub.On("captchaDecyphered"触发的问题。 有任何想法如何同步这个?
更新#1 小通知。无法避免使用充当SignalR客户端的中间同步WCF网络服务,因为非常特定的机器人坐在后面,可以与外部交互世界只能通过同步调用webservices。基本上在这种情况下,当机器人面对验证码时,它会调用Web服务,通​​过SignalR将其传递给UI进行手动识别 UPDATE#2 感谢@ Ken的鼓舞人心的建议让它通过将连接建立和hub方法调用封闭到单独的'Thread'然后等待'ManualResetEvent'来实现:

new Thread(() =>
{
    connection.Start().Wait();
    hub.Invoke<string>("DecypherCaptcha", new object[] { captcha });
}).Start();
sync.WaitOne();

以前一直试图从'Task'开始,假设它会隐式运行在单独的线程上,但没有运气。

3 个答案:

答案 0 :(得分:2)

您可以让SignalR服务器上的DecypherCaptcha hub方法将解密的验证码作为Task<string>返回,而不是调用captchaDecyphered

您可能希望使用TaskCompletionSource来帮助您创建适当的任务。基本上,您可以致电tcs.SetResult(deciphered)并返回tcs.Task,而不是致电Clients.Caller.captchaDecyphered(deciphered)

然后你的客户端代码就是:

[OperationContract]
public string DecypherCaptcha(string captcha)
{
    var connection = new HubConnection("http://localhost:51806");
    IHubProxy hub = connection.CreateHubProxy("robo");

    connection.Start().Wait();
    return hub.Invoke<string>("DecypherCaptcha", captcha).Result;
}

答案 1 :(得分:1)

你有几种选择。

(1)将对SignalR中心的请求分离到一个单独的线程上,可能使用静态ThreadPool类,然后添加所有ManualResetEvent内容。这样,当你等待SignalR方法返回时,它不会阻塞。

(2)使DecypherCaptcha方法异步。在我看来,DecypherCaptcha()旨在成为WCF方法,而WCF方法又包含SignalR方法。如果是这种情况,忘记这是否是一种明智的方法,当captchaDecyphered SignalR方法完成时,您仍然可以在客户端上调用WCF方法。但是如果它不是一个WCF方法,那么你可以让DecypherCaptcha()(a)返回Task<T>,并且只在Task标记captchaDecyphered时完成Func<T>完成或者(b)传递captchaDecyphered作为延续参数,并在{{1}}完成时调用。

通常,使异步编程变得困难的一个原因是,除了顶级方法之外,通常需要使每个调用异步方法的方法本身异步,一直在堆栈中上下,通过Async模式(讨厌),或continuation passing(更好)或通过Task对象+ async / await(可能是最好的)。因此,添加单个异步方法通常会导致应用程序发生重大变化。这是.NET 4.5中new async and await keywords如此有用的众多原因之一,因为它们有助于在开始使应用程序异步时封装必要的更改。

答案 2 :(得分:0)

您可以使用通用的Invoke方法,您可以在其中指定所需的结果类型。使用您可以使用的方法.Result等待结果。

string result = IHubProxy.Invoke<string>("GetString").Result;