尝试将消息推送到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'开始,假设它会隐式运行在单独的线程上,但没有运气。
答案 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;