Limite SignalR e Browser Connection

Ho fatto una semplice app con SignalR per i test. Quando la pagina viene caricata, chiama una funzione sul server, quella funzione chiama quindi una funzione client che stampa un messaggio sullo schermo. L’ho fatto per verificare che la funzione client e server funzioni e che la comunicazione SignalR funzioni correttamente.

Il mio problema è che se apro la stessa pagina su due diverse tabs (l’ho fatto in Chrome), la prima pagina viene caricata correttamente, ma la seconda pagina non chiama le funzioni del server – SOLO se chiudo la prima pagina.

Quindi, per quanto ho capito, il loro è probabilmente una limitazione della connessione che è legata al browser che non consente a SignalR di connettersi più di una volta (in realtà due, uno per la ricezione e uno per l’invio)

Aggiornamento: ho trovato le nostre altre tabs aperte, ma ora l’ho controllato e consente solo a 4 tabs / pagine di essere attive con le connessioni. Se provo a mettere la stessa pagina su una nuova scheda non viene inviato alcun dato, quando chiudo una delle altre tabs, la nuova scheda invia i dati immediatamente.

Quello che volevo sapere se c’è una soluzione per questo, perché voglio che questa connettività sia disponibile se l’utente decide di aprire la stessa pagina su due tabs o più.

Non credo che abbia qualcosa a che fare con IIS, perché da quello che so può accettare migliaia di connessioni.

Questo problema sarebbe meglio affrontato dalla futura specifica di Channel Messaging , che non è stata ancora implementata da alcun browser, ma sono riuscita a risolverlo limitando il numero di connessioni come descritto da Alex Ford e utilizzando localStorage come bus di messaggi tra tabs.

L’evento di storage consente di propagare i dati tra le tabs mantenendo aperta una singola connessione SignalR (impedendo così la saturazione della connessione). Chiamando localStorage.setItem('sharedKey', sharedData) si aumenterà l’evento di storage in tutte le altre tabs (non nel chiamante):

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

È ansible verificare if ($.connection.hub.state === 1) per determinare se una determinata scheda deve notificare le altre tabs tramite localStorage (per gentile concessione di Alex) per evitare duplicate chiamate localStorage.setItem .

Facebook supera questa limitazione del browser offrendo collegamenti persistenti su diversi sottodomini, ma ciò può complicare la distribuzione e il testing.

Avvertenze

Connessioni precedenti: nella soluzione di Alex, è necessario fare attenzione a che Disconnect() non venga chiamato (ad es. Eccezione) e si riempie il bucket (o il repository) HubConnections con connessioni hub precedenti. Se l’ID sessione non cambia (può accadere), ciò potrebbe impedire ai nuovi client di stabilire una connessione SignalR anche se nessuno è attivo. In alternativa, timestamp nuove connessioni e hanno una scadenza di scorrimento per minimizzare il potenziale impatto.

Blocco: localStorage può essere sobject a condizioni di gara in quanto non implementa alcun blocco come descritto qui .

Per supportare diversi tipi di eventi, dovresti codificare un eventType nei tuoi messaggi JSON e testarlo per l’evento di storage .

fallback

Se non è ansible stabilire una connessione SignalR, ricado al polling del server ogni 45 secondi per recuperare un conteggio delle notifiche.

Se non si desidera utilizzare localStorage, è ansible utilizzare i cookie, ma non è così pulito.

Per espandere la risposta di @ FreshCode, ecco come ho implementato la sua idea.

Ho avuto bisogno di passare due diverse azioni tra le tabs. Posso impostare notifiche o rimuovere notifiche. Queste notifiche vengono ricevute dal browser e memorizzate come timeout che si triggersno in un momento specifico. La prima scheda ha la connessione SignalR e tutte le altre no. Un problema che ho dovuto superare è che l’evento “storage” si triggers indipendentemente dall’azione che intendevo eseguire (set / remove).

Quello che ho finito è stato passare un object JSON personalizzato con una proprietà contenente l’azione che volevo eseguire:

 $(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); }); 

In questo modo ogni volta che imposto un elemento nell’archivio locale, specificherò solo l’azione che deve essere eseguita e solo quell’azione verrà eseguita nelle altre tabs. Ad esempio, se aggiorno una notifica è una combinazione di entrambe le azioni quando viene ricevuta dal client. Rimuove la notifica e imposta la notifica con i valori aggiornati. Quindi sono state fatte due chiamate a 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 } 

Allo stesso modo, la funzione setNotification .

 function setNotification(notification) { if ($.connection.hub.state === 1) { var updateInfo = { action: 'setNotification', notification: notification }; localStorage.setItem('updateInfo', JSON.stringify(updateInfo)); } // brevity brevity } 

Ho creato l’utilità IWC-SignalR che consente di avere una singola connessione SignalR per tutte le windows (tabs) della stessa applicazione.

Come funziona

Una delle windows diventa proprietario della connessione (scelta casualmente) e contiene la vera connessione SignalR. Se il proprietario della connessione viene chiuso o arrestato in modo anomalo, un’altra finestra diventa proprietario della connessione. Ciò avviene automaticamente. La comunicazione tra windows è effettuata tramite la libreria di comunicazione tra windows (basata su localStorage ). Questa libreria fornisce funzionalità per comunicare tra windows come tra processi paralleli (blocchi, dati condivisi, bus eventi …). Spero che sarà utile per qualcuno.