2

尝试将消息推送到 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;
}

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

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

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

4

3 回答 3

2

您可以让 SignalR 服务器上的hub 方法在调用DecypherCaptcha时返回解密的验证码作为 a 。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;
}
于 2013-01-29T20:09:44.730 回答
1

你有几个选择。

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

(2) 使DecypherCaptcha方法异步。在我看来,它DecypherCaptcha()旨在成为一个 WCF 方法,而该方法又包装了一个 SignalR 方法。captchaDecyphered如果是这种情况,暂时忘记这是否是一种明智的方法,当SignalR 方法完成时,您仍然可以在客户端上调用 WCF 方法。但是,如果它不打算成为 WCF 方法,那么您可以DecypherCaptcha()(a)返回 a ,并且仅在完成时将其Task<T>标记为完成;或 (b) 传入 a作为延续参数,并在完成时调用它。TaskcaptchaDecypheredFunc<T>captchaDecyphered

通常,使异步编程变得困难的一件事是,除了非常顶层的方法之外,您通常需要使调用异步方法的每个方法本身都是异步的,一直到堆栈的上下,或者通过异步模式(讨厌),或继续传递(更好)或通过 Task 对象 + async/await(可能是最好的)。因此,添加单个异步方法通常会导致您的应用程序发生重大变化,一直如此。这就是 .NET 4.5 中新的 async 和 await 关键字如此有用的众多原因之一,因为它们有助于在您开始使应用程序异步时封装必要的更改。

于 2013-01-29T16:40:40.640 回答
0

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

string result = IHubProxy.Invoke<string>("GetString").Result;
于 2017-02-17T06:42:09.163 回答