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; }メソッドが終了した後、式はサーバーから正常にトリガーされます。フラグを
追加しても、実行がフリーズして発火を防止する問題は解決しません。これを同期する方法はありますか?UPDATE#1小さなお知らせ。SignalR クライアントとして機能する中間同期 WCF Web サービスの使用を避けることはできません。これは、Web サービスを同期的に呼び出すことによってのみ外界と対話できる非常に特殊なロボットが後ろに座っているためです。基本的にこのシナリオでは、ロボットがキャプチャに直面すると、手動認識のために SignalR を介して UI に渡す Web サービスを呼び出します。更新#2ManualResetEventWaitOne()hub.On("captchaDecyphered"

@Ken の感動的なアドバイスのおかげで、接続の確立とハブ メソッドの呼び出しを別の「スレッド」に囲み、続いて「ManualResetEvent」で待機することで機能するようになりました。

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

以前は、暗黙的に別のスレッドで実行されると仮定して「タスク」から開始しようとしましたが、うまくいきませんでした。

4

3 に答える 3

2

SignalR サーバーのハブ メソッドは、呼び出し時に代わりにDecypherCaptcha解読されたキャプチャを として返すことができます。Task<string>captchaDecyphered

適切なタスクを作成するために、 TaskCompletionSourceを使用することができます。基本的に、 を呼び出す代わりに、呼び出しtcs.SetResult(deciphered)て返すことができます。tcs.TaskClients.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()SignalR メソッドをラップする WCF メソッドを意図しているように見えます。その場合、これが賢明なアプローチであるかどうかを少し忘れてしまいますが、captchaDecypheredSignalR メソッドの完了時にクライアントで WCF メソッドを呼び出すことができます。しかし、それが WCF メソッドであることを意図していない場合はDecypherCaptcha()、(a) を返し、が完了したときにTask<T>のみフラグを立てることができます。または (b)継続パラメーターとして a を渡し、完了時にそれを呼び出します。TaskcaptchaDecypheredFunc<T>captchaDecyphered

一般に、非同期プログラミングを難しくしている原因の 1 つは、最上位のメソッドを除いて、非同期メソッド自体を呼び出すすべてのメソッドを非同期にする必要があることです。非同期パターン (厄介)、または継続渡し(より良い)、または Task オブジェクト + async/await (おそらく最良) を使用します。そのため、単一の非同期メソッドを追加すると、多くの場合、アプリケーション全体が大幅に変更されます。これが、.NET 4.5 の新しい async および await キーワードが非常に役立つ多くの理由の 1 つです。これらのキーワードは、アプリケーションの非同期化を開始するときに必要な変更をカプセル化するのに役立つからです。

于 2013-01-29T16:40:40.640 に答える