1

SignalR には、値を返すクライアント メソッドを持つ機能がありません。そのため、これを可能にするヘルパー クラスを作成しようとしています。

だから、これは私がやろうとしていることです:

  1. サーバー側: クライアント メソッドを呼び出し、一意のリクエスト ID を提供するClient(clientId).GetValue(requestId)
  2. サーバー側: requestId を保存し、次を使用して応答を待ちますManualResetEvent
  3. クライアント側: インサイドvoid GetValue(Guid requestId)コール サーバー メソッドhubProxy.Invoke("GetValueFinished", requestId, 10)
  4. サーバー側: requestId で待機メソッドを検索 => 戻り値を設定 => シグナルを設定
  5. サーバー側: メソッドは vor を待機しなくなりManualResetEvent、取得した値を返します。

残念ながら動作させることができます。これが私のコードです:

public static class MethodHandler
{
    private static ConcurrentDictionary<Guid, ReturnWaiter> runningMethodWaiters = new ConcurrentDictionary<Guid,ReturnWaiter>();

    public static TResult GetValue<TResult>(Action<Guid> requestValue)
    {
        Guid key = Guid.NewGuid();
        ReturnWaiter returnWaiter = new ReturnWaiter(key);
        runningMethodWaiters.TryAdd(key, returnWaiter);
        requestValue.Invoke(key);
        returnWaiter.Signal.WaitOne();
        return (TResult)returnWaiter.Value;
    }

    public static void GetValueResult(Guid key, object value)
    {
        ReturnWaiter waiter;
        if (runningMethodWaiters.TryRemove(key, out waiter))
        {
            waiter.Value = value;
        }
    }
}

internal class ReturnWaiter 
{
    private ManualResetEvent _signal  = new ManualResetEvent(false);
    public ManualResetEvent Signal { get { return _signal; } }
    public Guid Key {get; private set;}

    public ReturnWaiter(Guid key)
    {
        Key = key;
    }

    private object _value;
    public object Value 
    {
        get { return _value; }
        set 
        {
            _value = value;
            Signal.Set();
        }
    }
}

このMethodHandlerクラスを使用して、サーバー側に 2 つのメソッドが必要です。

public int GetValue(string clientId)
{
    return MethodHandler.GetValue<int>(key => Clients(clientId).Client.GetValue(key));
}

public void GetValueResult(Guid key, object value)
{
    MethodHandler.GetValueResult(key, value);
}

クライアント側の実装は次のようになります。

// Method registration
_hubProxy.On("GetValue", new Action<Guid>(GetValue));

public void GetValue(Guid requestId)
{
    int result = 10;
    _hubConnection.Invoke("GetValueResult", requestId, result);
}

問題:
サーバー側を呼び出す場合GetValue("clientid")。クライアント メソッドは呼び出されません。コメントアウトするreturnWaiter.Signal.WaitOne();と、クライアント側GetValueが呼び出され、サーバー側GetValueResultが呼び出されます。しかしもちろん、今回はメソッドはすでに返されています。

に関係していると思いましたManualResetEventが、使用してもwhile(!returnWaiter.HasValue) Thread.Sleep(100);この問題は解決しません。

この問題を解決する方法はありますか?

前もって感謝します!

4

2 に答える 2

3

まず、どうすれば同期できるようになるかを尋ねるよりも、何をしようとしているのかを教えていただければ、適切な方法を提案できるのではないかと思います。

あなたはあなたの方法を示していませんMethodHandler::Retrieveが、私はそれがどのように見えるかをほとんど推測することができ、それは本当の問題でさえありません. これは本当に悪い考えだということを、できるだけ良い方法で伝えなければなりません。それは単にスケーリングすることはありません。ManualResetEventブロックを提供するためにマシン固有のリソース (たとえば、 の背後にあるカーネル オブジェクト) に依存しているため、これは単一の SignalR サーバー インスタンスでのみ機能します。要件を満たすために 1 台のサーバーを超えて拡張する必要はないかもしれませんが、これは 1 台のサーバーであってもリソースの無駄遣いです。

requestId実際には、クライアントが を相関識別子としてコールバックするという正しい軌道に乗っています。その相関関係を使用して、サーバー側で実行中のプロセスの論理的な実行を再開できないのはなぜですか? そうすれば、メッセージがクライアントに配信され、処理され、サンプル内のフォローアップ メッセージGetValueResultがサーバー インスタンスに送り返されるのを待っている間、リソースが保持されることはありません。

于 2013-07-12T21:22:02.757 に答える