20

テスト用に SignalR を使用して簡単なアプリを作成しました。ページが読み込まれると、サーバー上の関数が呼び出され、その関数がクライアント関数を呼び出して、画面にメッセージを出力します。クライアントとサーバーの両方の機能が動作し、SignalR 通信が正常に動作することを確認するためにこれを行いました。

私の問題は、2 つの異なるタブで同じページを開くと (Chrome で行った場合)、最初のページは正常に読み込まれますが、2 番目のページはサーバーの機能を呼び出さないことです。最初のページを閉じた場合のみです。

したがって、私が理解している限り、それらはおそらく SignalR が複数回接続することを許可しないブラウザーに関連する接続制限です (実際には、受信用と送信用の 2 つ)。

更新: 他のタブが開いていることがわかりましたが、確認したところ、接続でアクティブにできるタブ/ページは 4 つだけです。同じページを新しいタブに配置しようとすると、データが送信されません。他のタブのいずれかを閉じると、新しいタブはすぐにデータを送信します。

ユーザーが2つ以上のタブで同じページを開くことにした場合にこの接続を利用できるようにしたいので、その解決策があるかどうか知りたかったこと。

私が知っている限り、何千もの接続を受け入れることができるので、IIS とは何の関係もないと思います。

4

4 に答える 4

21

この問題は、これまでどのブラウザーにも実装されていない将来のChannel Messaging仕様で対処するのが最善ですが、Alex Ford が説明したように接続数を制限し、localStorageタブ間のメッセージ バスとして使用することで解決できました。 .

このstorageイベントを使用すると、1 つの SignalR 接続を開いたままにして、タブ間でデータを伝達できます (それにより、接続の飽和を防ぎます)。呼び出すlocalStorage.setItem('sharedKey', sharedData)と、storage他のすべてのタブ (呼び出し元ではない) でイベントが発生します。

$(window).bind('storage', function (e) {
    var sharedData = localStorage.getItem('sharedKey');
    if (sharedData !== null)
        console.log(
            'A tab called localStorage.setItem("sharedData",'+sharedData+')'
        );
});

重複した呼び出しif ($.connection.hub.state === 1)を防ぐために、特定のタブが localStorage (Alex の好意による) を介して他のタブに通知する必要があるかどうかをテストして判断できます。localStorage.setItem

Facebook は、いくつかのサブドメインで永続的な接続を提供することにより、このブラウザーの制限を克服していますが、これにより展開とテストが複雑になる可能性があります。

注意事項

古い接続:アレックスのソリューションでは、呼び出されないように注意する必要がありDisconnect()(例外など)、HubConnectionsバケット (またはリポジトリ) が古いハブ接続でいっぱいになります。セッション ID が変更されない (発生する可能性がある) 場合、アクティブなクライアントがなくても、新しいクライアントが SignalR 接続を確立できない可能性があります。または、新しい接続にタイムスタンプを設定し、潜在的な影響を最小限に抑えるために有効期限をスライドさせます。

ロック: ここで説明されているlocalStorageようにロックを実装していないため、競合状態になる可能性があります。

さまざまなタイプのイベントをサポートするには、JSON メッセージでeventTypeをエンコードし、storageイベントでテストする必要があります。

フォールバック

SignalR 接続を確立できない場合は、フォールバックして 45 秒ごとにサーバーをポーリングし、通知カウントを取得します。

localStorage を使用したくない場合は、Cookie を使用できますが、クリーンではありません。

于 2012-10-23T18:35:07.393 に答える
4

同じアプリケーションのすべてのウィンドウ (タブ) に対して単一の SignalR 接続を可能にするIWC-SignalRユーティリティを作成しました。

使い方

ウィンドウの 1 つが接続所有者 (ランダムに選択) になり、実際の SignalR 接続を保持します。接続所有者が閉じられるかクラッシュすると、別のウィンドウが接続所有者になります - これは自動的に行われます。ウィンドウ間通信は、ウィンドウ間通信ライブラリ(ベース)によって行われますlocalStorage。このライブラリは、ウィンドウ間および並列プロセス (ロック、共有データ、イベント バスなど) 間で通信する機能を提供します。誰かに役立つことを願っています。

于 2015-02-02T22:28:19.010 に答える
3

@FreshCodeの答えを拡張するために、これが私が彼のアイデアを実装した方法です。

タブ間で2つの異なるアクションを渡す必要がありました。通知を設定するか、通知を削除することができます。これらの通知はブラウザによって受信され、指定された時間に発生するタイムアウトとして保存されます。最初のタブにはSignalR接続があり、他のすべてのタブにはありません。私が克服しなければならなかった問題の1つは、実行しようとしていたアクション(設定/削除)に関係なく、「ストレージ」イベントが発生することでした。

私がやったことは、実行したいアクションを含むプロパティを持つカスタムJSONオブジェクトを渡すことでした。

$(window).bind('storage', function () {
    var updateInfo = JSON.parse(localStorage.getItem('updateInfo'));
    if (updateInfo.action == 'removeNotification')
        removeNotification(updateInfo.notificationId);
    else if (updateInfo.action == 'setNotification')
        setNotification(updateInfo.notification);
});

このように、ローカルストレージにアイテムを設定するたびに、実行する必要のあるアクションを指定するだけで、そのアクションのみが他のタブで実行されます。たとえば、通知を更新すると、クライアントが通知を受信したときに両方のアクションが組み合わされます。通知を削除し、更新された値で通知を設定します。したがって、2つの呼び出しlocalStorage.setItemが行われています。

function removeNotification(id) {
    // Check if signalR is connected. If so, I am the tab that will update
    // the other tabs.
    if ($.connection.hub.state === 1) {
        var updateInfo = {
            action: 'removeNotification',
            notificationId: id
        };
        localStorage.setItem('updateInfo', JSON.stringify(updateInfo));
    }
    // brevity brevity
}

同様に、setNotification関数。

function setNotification(notification) {
    if ($.connection.hub.state === 1) {
        var updateInfo = {
            action: 'setNotification',
            notification: notification
        };
        localStorage.setItem('updateInfo', JSON.stringify(updateInfo));
    }
    // brevity brevity
}
于 2012-10-24T08:52:42.637 に答える