web-dev-qa-db-ja.com

SignalR 2.0 .NETクライアントをサーバーハブに再接続するためのベストプラクティス

さまざまな種類の切断を処理する必要があるモバイルアプリケーションで.NETクライアントと共にSignalR 2.0を使用しています。 SignalRクライアントは自動的に再接続する場合があります。また、HubConnection.Start()を再度呼び出して直接再接続する必要がある場合もあります。

SignalRは時々魔法のように自動再接続するので、機能や設定が欠落しているかどうか疑問に思っていますか?

自動的に再接続するクライアントを設定する最良の方法は何ですか?


Closed()イベントを処理し、n秒後に接続するjavascriptの例を見てきました。推奨されるアプローチはありますか?

documentation とSignalR接続の有効期間に関するいくつかの記事を読みましたが、クライアントの再接続の処理方法についてはまだわかりません。

74
Ender2050

私はついにこれを理解しました。この質問を始めてから学んだことは次のとおりです。

背景:Xamarin/Monotouchと.NET SignalR 2.0.3クライアントを使用してiOSアプリを構築しています。デフォルトのSignalRプロトコルを使用していますが、Webソケットの代わりにSSEを使用しているようです。 Xamarin/MonotouchでWebソケットを使用できるかどうかはまだわかりません。すべてがAzure Webサイトを使用してホストされます。

SignalRサーバーにすばやく再接続するにはアプリが必要でしたが、接続が自動的に再接続されなかったり、再接続に正確に30秒かかったりする問題が引き続き発生しました(基になるプロトコルタイムアウトのため)。

最終的にテストを行ったシナリオは3つありました。

シナリオA-アプリが最初にロードされたときに接続します。これは初日から問題なく動作しました。接続は、3Gモバイル接続でも0.25秒未満で完了します。 (ラジオがすでにオンになっていると仮定)

シナリオB-アプリが30秒間アイドル/クローズされた後にSignalRサーバーに再接続します。このシナリオでは、SignalRクライアントは最終的にサーバーに再接続します特別な作業なしで独自に-しかし、再接続を試みる前にちょうど30秒待つようです。 (アプリには遅すぎる)

この30秒間の待機中に、HubConnection.Start()の呼び出しを試みましたが、効果はありませんでした。また、HubConnection.Stop()の呼び出しにも30秒かかります。 解決されたように見えるSignalRサイトの関連バグ が見つかりましたが、v2.0.3でも同じ問題が残っています。

シナリオC-アプリが120秒以上アイドル/クローズされた後、SignalRサーバーに再接続します。このシナリオでは、SignalRトランスポートプロトコルは既にタイムアウトしています。クライアントが自動的に再接続することはありません。これは、クライアントが時々単独で再接続する場合がある理由を説明しています。良いニュースは、HubConnection.Start()を呼び出すと、シナリオAのようにほぼ瞬時に機能することです。

そのため、アプリが30秒閉じられているか120秒以上閉じられているかに基づいて、再接続条件が異なることに気付くまでに少し時間がかかりました。また、SignalRトレースログは、基になるプロトコルで何が起こっているかを明らかにしますが、コードでトランスポートレベルイベントを処理する方法があるとは思いません。 (Closed()イベントは、シナリオBで30秒後に、シナリオCで即座に起動します。これらの再接続待機期間中にStateプロパティは「Connected」と表示します。他の関連するイベントまたはメソッドはありません)

解決策:解決策は明白です。 SignalRが再接続のマジックを行うのを待っていません。代わりに、アプリがアクティブになったとき、または電話のネットワーク接続が復元されたときに、単にイベントをクリーンアップし、HubConnectionの参照を解除します(30秒かかるため破棄できません。できればガベージコレクションが処理します) )および新しいインスタンスを作成します。今、すべてがうまく機能しています。何らかの理由で、新しいインスタンスを作成するだけでなく、永続的な接続を再利用して再接続する必要があると考えました。

65
Ender2050

切断されたイベントにタイマーを設定して自動的に再接続を試みることは、私が知っている唯一の方法です。

Javascriptでは次のように行われます:

$.connection.hub.disconnected(function() {
   setTimeout(function() {
       $.connection.hub.start();
   }, 5000); // Restart connection after 5 seconds.
});

これは、ドキュメントで推奨されるアプローチです。

http://www.asp.net/signalr/overview/signalr-20/hubs-api/handling-connection-lifetime-events#clientdisconnect

40

OPは。NETクライアント(以下のwinform実装)を要求するため、

private async Task<bool> ConnectToSignalRServer()
{
    bool connected = false;
    try
    {
        Connection = new HubConnection("server url");
        Hub = Connection.CreateHubProxy("MyHub");
        await Connection.Start();

        //See @Oran Dennison's comment on @KingOfHypocrites's answer
        if (Connection.State == ConnectionState.Connected)
        {
            connected = true;
            Connection.Closed += Connection_Closed;
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Error: {ex.Message}");
    }
    return connected;
}

private async void Connection_Closed()
{   // A global variable being set in "Form_closing" event 
    // of Form, check if form not closed explicitly to prevent a possible deadlock.
    if(!IsFormClosed) 
    {
        // specify a retry duration
        TimeSpan retryDuration = TimeSpan.FromSeconds(30);
        DateTime retryTill = DateTime.UtcNow.Add(retryDuration);

        while (DateTime.UtcNow < retryTill)
        {
            bool connected = await ConnectToSignalRServer();
            if (connected)
                return;
        }
        Console.WriteLine("Connection closed")
    }
}
11
ibubi
Multiple query string
self.hubConnection = $.hubConnection();
self.hubConnection.qs = { param1: value, param2: value };

から:

Signalr-サーバーでクエリ文字列を読み取れません

0
AShah