Informazioni e gestione degli eventi di durata della connessione in SignalR 1.x

di Patrick Fletcher, Tom Dykstra

Avviso

Questa documentazione non è per la versione più recente di SignalR. Esaminare ASP.NET Core SignalR.

Questo articolo offre una panoramica degli eventi di connessione, riconnessione e disconnessione di SignalR che è possibile gestire e timeout e mantenere le impostazioni di keepalive che è possibile configurare.

L'articolo presuppone che si abbia già una conoscenza degli eventi di durata della connessione e SignalR. Per un'introduzione a SignalR, vedere SignalR - Panoramica - Introduzione. Per elenchi di eventi di durata della connessione, vedere le risorse seguenti:

Panoramica

In questo articolo sono contenute le sezioni seguenti:

I collegamenti agli argomenti di riferimento per le API sono alla versione .NET 4.5 dell'API. Se si usa .NET 4, vedere la versione .NET 4 degli argomenti dell'API.

Terminologia e scenari relativi alla durata della connessione

Il OnReconnected gestore eventi in un hub SignalR può essere eseguito direttamente dopo ma non dopo OnDisconnectedOnConnected per un determinato client. Il motivo per cui è possibile avere una riconnessione senza una disconnessione è che esistono diversi modi in cui la parola "connessione" viene usata in SignalR.

Connessioni SignalR, connessioni di trasporto e connessioni fisiche

Questo articolo distinguerà le connessioni SignalR, le connessioni di trasporto e le connessioni fisiche:

  • La connessione SignalR fa riferimento a una relazione logica tra un client e un URL del server, gestita dall'API SignalR e identificata in modo univoco da un ID connessione. I dati relativi a questa relazione vengono mantenuti da SignalR e vengono usati per stabilire una connessione di trasporto. La relazione termina e SignalR elimina i dati quando il client chiama il Stop metodo o un limite di timeout viene raggiunto mentre SignalR tenta di ristabilire una connessione di trasporto persa.
  • La connessione di trasporto fa riferimento a una relazione logica tra un client e un server, gestita da una delle quattro API di trasporto: WebSocket, eventi inviati dal server, frame per sempre o polling lungo. SignalR usa l'API di trasporto per creare una connessione di trasporto e l'API di trasporto dipende dall'esistenza di una connessione di rete fisica per creare la connessione di trasporto. La connessione di trasporto termina quando SignalR termina o quando l'API di trasporto rileva che la connessione fisica viene interrotta.
  • La connessione fisica si riferisce ai collegamenti di rete fisica, i fili, i segnali wireless, i router e così via. - che facilitano la comunicazione tra un computer client e un computer server. La connessione fisica deve essere presente per stabilire una connessione di trasporto e deve essere stabilita una connessione di trasporto per stabilire una connessione SignalR. Tuttavia, l'interruzione della connessione fisica non termina sempre la connessione di trasporto o la connessione SignalR, come illustrato più avanti in questo argomento.

Nel diagramma seguente la connessione SignalR è rappresentata dall'API Hubs e dal livello Api PersistentConnection SignalR, la connessione di trasporto è rappresentata dal livello Transports e la connessione fisica è rappresentata dalle linee tra il server e i client.

Diagramma dell'architettura signalR

Quando si chiama il Start metodo in un client SignalR, si fornisce il codice client SignalR con tutte le informazioni necessarie per stabilire una connessione fisica a un server. Il codice client SignalR usa queste informazioni per effettuare una richiesta HTTP e stabilire una connessione fisica che usa uno dei quattro metodi di trasporto. Se la connessione di trasporto ha esito negativo o il server non riesce, la connessione SignalR non viene interrotta immediatamente perché il client ha ancora le informazioni necessarie per ristabilire automaticamente una nuova connessione di trasporto allo stesso URL SignalR. In questo scenario non viene coinvolto alcun intervento dell'applicazione utente e quando il codice client SignalR stabilisce una nuova connessione di trasporto, non avvia una nuova connessione SignalR. La continuità della connessione SignalR si riflette nel fatto che l'ID connessione, che viene creato quando si chiama il Start metodo, non cambia.

Il OnReconnected gestore eventi nell'hub viene eseguito quando una connessione di trasporto viene riabilita automaticamente dopo la perdita. Il OnDisconnected gestore eventi viene eseguito alla fine di una connessione SignalR. Una connessione SignalR può terminare in uno dei modi seguenti:

  • Se il client chiama il Stop metodo, viene inviato un messaggio di arresto al server e il client e il server terminano immediatamente la connessione SignalR.
  • Dopo aver perso la connettività tra client e server, il client tenta di riconnettersi e il server attende la riconnessione del client. Se i tentativi di riconnessione non sono riusciti e il periodo di timeout disconnessione termina, sia il client che il server terminano la connessione SignalR. Il client smette di riconnettersi e il server elimina la relativa rappresentazione della connessione SignalR.
  • Se il client smette di eseguire senza avere la possibilità di chiamare il Stop metodo, il server attende la riconnessione del client e quindi termina la connessione SignalR dopo il periodo di timeout disconnessione.
  • Se il server si arresta in esecuzione, il client tenta di riconnettersi (ricreare la connessione di trasporto) e quindi termina la connessione SignalR dopo il periodo di timeout disconnessione.

Quando non sono presenti problemi di connessione e l'applicazione utente termina la connessione SignalR chiamando il Stop metodo, la connessione SignalR e la connessione di trasporto iniziano e terminano contemporaneamente. Le sezioni seguenti descrivono in dettaglio gli altri scenari.

Scenari di disconnessione del trasporto

Le connessioni fisiche potrebbero essere lente o potrebbero verificarsi interruzioni nella connettività. A seconda di fattori come la lunghezza dell'interruzione, la connessione al trasporto potrebbe essere eliminata. SignalR tenta quindi di ristabilire la connessione di trasporto. A volte l'API di connessione di trasporto rileva l'interruzione e elimina la connessione di trasporto e SignalR rileva immediatamente che la connessione viene persa. In altri scenari, né l'API di connessione di trasporto né SignalR diventa consapevole immediatamente che la connettività è stata persa. Per tutti i trasporti tranne il polling lungo, il client SignalR usa una funzione denominata keepalive per verificare la perdita di connettività che l'API di trasporto non è in grado di rilevare. Per informazioni sulle connessioni di polling lunghe, vedere Timeout e le impostazioni keepalive più avanti in questo argomento.

Quando una connessione è inattiva, il server invia periodicamente un pacchetto keepalive al client. A partire dalla data in cui viene scritto questo articolo, la frequenza predefinita è ogni 10 secondi. Ascoltando questi pacchetti, i client possono stabilire se si verifica un problema di connessione. Se un pacchetto keepalive non viene ricevuto quando previsto, dopo un breve periodo di tempo il client presuppone che si verifichino problemi di connessione, ad esempio lentezza o interruzioni. Se il keepalive non viene ancora ricevuto dopo un periodo di tempo più lungo, il client presuppone che la connessione sia stata eliminata e inizi a provare a riconnettersi.

Il diagramma seguente illustra gli eventi client e server generati in uno scenario tipico quando si verificano problemi con la connessione fisica non immediatamente riconosciuta dall'API di trasporto. Il diagramma si applica alle circostanze seguenti:

  • Il trasporto è WebSockets, per sempre frame o eventi inviati dal server.
  • Esistono diversi periodi di interruzione nella connessione di rete fisica.
  • L'API di trasporto non diventa consapevole delle interruzioni, quindi SignalR si basa sulla funzionalità keepalive per rilevarli.

Disconnessione del trasporto

Se il client entra in modalità di riconnessione, ma non riesce a stabilire una connessione di trasporto entro il limite di timeout disconnessione, il server termina la connessione SignalR. In questo caso, il server esegue il metodo dell'hub OnDisconnected e accoda un messaggio disconnesso per inviare al client nel caso in cui il client riesca a connettersi in un secondo momento. Se il client esegue la riconnessione, riceve il comando disconnesso e chiama il Stop metodo. In questo scenario non OnReconnected viene eseguito quando il client si riconnette e OnDisconnected non viene eseguito quando il client chiama Stop. Il diagramma seguente illustra questo scenario.

Interruzioni del trasporto - Timeout del server

Gli eventi di durata della connessione SignalR generati nel client sono i seguenti:

  • ConnectionSlow evento client.

    Generato quando è stata ricevuta una proporzione predefinita del periodo di timeout keepalive dopo l'ultimo messaggio o il ping keepalive. Il periodo di avviso di timeout keepalive predefinito è 2/3 del timeout keepalive. Il timeout keepalive è di 20 secondi, quindi l'avviso si verifica a circa 13 secondi.

    Per impostazione predefinita, il server invia ping keepalive ogni 10 secondi e il client controlla il ping keepalive circa ogni 2 secondi (un terzo della differenza tra il valore di timeout keepalive e il valore di avviso di timeout keepalive).

    Se l'API di trasporto diventa consapevole di una disconnessione, SignalR potrebbe essere informato della disconnessione prima del periodo di avviso di timeout keepalive. In tal caso, l'evento ConnectionSlow non verrà generato e SignalR passerebbe direttamente all'evento Reconnecting .

  • Reconnecting evento client.

    Generato quando (a) l'API di trasporto rileva che la connessione viene persa o (b) il periodo di timeout keepalive è passato dall'ultimo messaggio o ping keepalive ricevuto. Il codice client SignalR inizia a provare a riconnettersi. È possibile gestire questo evento se si desidera che l'applicazione eseere un'azione quando si perde una connessione di trasporto. Il periodo di timeout keepalive predefinito è attualmente di 20 secondi.

    Se il codice client tenta di chiamare un metodo hub mentre SignalR è in modalità di riconnessione, SignalR tenterà di inviare il comando. Nella maggior parte dei casi, tali tentativi avranno esito negativo, ma in alcune circostanze potrebbero avere esito positivo. Per gli eventi inviati dal server, per sempre frame e per i trasporti di polling lunghi, SignalR usa due canali di comunicazione, uno usato dal client per inviare messaggi e uno usato per ricevere messaggi. Il canale usato per la ricezione è quello aperto in modo permanente e questo è quello chiuso quando la connessione fisica viene interrotta. Il canale usato per l'invio rimane disponibile, quindi se viene ripristinata la connettività fisica, una chiamata al metodo dal client al server potrebbe avere esito positivo prima che il canale di ricezione venga ristabilito. Il valore restituito non viene ricevuto fino a quando SignalR riapre il canale usato per la ricezione.

  • Reconnected evento client.

    Generato quando la connessione di trasporto viene ristabilita. Il OnReconnected gestore eventi nell'hub viene eseguito.

  • Closed evento client (disconnected evento in JavaScript).

    Generato alla scadenza del periodo di timeout di disconnessione durante il tentativo di riconnessione del codice client SignalR dopo la perdita della connessione di trasporto. Il timeout di disconnessione predefinito è 30 secondi. Questo evento viene generato anche al termine della connessione perché viene chiamato il Stop metodo .

Interruzioni della connessione di trasporto non rilevate dall'API di trasporto e non ritardare la ricezione di ping keepalive dal server per più tempo del periodo di avviso di timeout keepalive potrebbe non causare la generazione di eventi di durata della connessione.

Alcuni ambienti di rete chiudono deliberatamente le connessioni inattive e un'altra funzione dei pacchetti keepalive consiste nell'evitare questo problema consentendo a queste reti di sapere che una connessione SignalR è in uso. In casi estremi la frequenza predefinita dei ping keepalive potrebbe non essere sufficiente per impedire le connessioni chiuse. In tal caso è possibile configurare ping keepalive da inviare più spesso. Per altre informazioni, vedere Timeout e keepalive settings più avanti in questo argomento.

Nota

Importante

La sequenza di eventi descritti qui non è garantita. SignalR tenta ogni tentativo di generare eventi di durata della connessione in modo prevedibile in base a questo schema, ma esistono molte varianti di eventi di rete e molti modi in cui i framework di comunicazione sottostanti, ad esempio le API di trasporto, li gestiscono. Ad esempio, l'evento Reconnected potrebbe non essere generato quando il client si riconnette o il OnConnected gestore nel server potrebbe essere eseguito quando il tentativo di stabilire una connessione non riesce. In questo argomento vengono descritti solo gli effetti che normalmente verrebbero prodotti da determinate circostanze tipiche.

Scenari di disconnessione client

In un client browser il codice client SignalR che gestisce una connessione SignalR viene eseguito nel contesto JavaScript di una pagina Web. Ecco perché la connessione SignalR deve terminare quando si passa da una pagina a un'altra ed è per questo che si hanno più connessioni con più ID di connessione se ci si connette da più finestre o schede del browser. Quando l'utente chiude una finestra o una scheda del browser o passa a una nuova pagina o aggiorna la pagina, la connessione SignalR termina immediatamente perché il codice client SignalR gestisce l'evento del browser e chiama il Stop metodo. In questi scenari o in qualsiasi piattaforma client quando l'applicazione chiama il Stop metodo , il OnDisconnected gestore eventi viene eseguito immediatamente sul server e il client genera l'evento Closed (l'evento è denominato disconnected in JavaScript).

Se un'applicazione client o il computer in cui è in esecuzione si arresta in modo anomalo o passa alla sospensione (ad esempio, quando l'utente chiude il portatile), il server non viene informato di ciò che è accaduto. Per quanto riguarda il server, la perdita del client potrebbe essere dovuta a un'interruzione della connettività e il client potrebbe tentare di riconnettersi. Pertanto, in questi scenari il server attende di consentire al client di riconnettersi e OnDisconnected non viene eseguito fino alla scadenza del periodo di timeout di disconnessione (circa 30 secondi per impostazione predefinita). Il diagramma seguente illustra questo scenario.

Errore del computer client

Scenari di disconnessione del server

Quando un server passa offline, viene riavviato, ha esito negativo, il dominio dell'app viene riciclato e così via. -- il risultato potrebbe essere simile a una connessione persa o l'API di trasporto e SignalR potrebbero sapere immediatamente che il server è scomparso e SignalR potrebbe iniziare a tentare di riconnettersi senza generare l'evento ConnectionSlow . Se il client passa alla modalità di riconnessione e se il server viene ripristinato o riavviato o viene portato online un nuovo server prima della scadenza del periodo di timeout di disconnessione, il client si riconnetterà al server ripristinato o nuovo. In tal caso, la connessione SignalR continua sul client e l'evento Reconnected viene generato. Nel primo server, OnDisconnected non viene mai eseguito e nel nuovo server OnReconnected viene eseguito anche se OnConnected non è mai stato eseguito per tale client nel server in precedenza. L'effetto è lo stesso se il client si riconnette allo stesso server dopo un riavvio o un riciclo del dominio dell'app, perché quando il server riavvia non ha memoria dell'attività di connessione precedente. Il diagramma seguente presuppone che l'API di trasporto acquisisca immediatamente la connessione persa, quindi l'evento ConnectionSlow non viene generato.

Errore del server e riconnessione

Se un server non diventa disponibile entro il periodo di timeout di disconnessione, la connessione SignalR termina. In questo scenario l'evento Closed (disconnected nei client JavaScript) viene generato nel client, ma OnDisconnected non viene mai chiamato nel server. Il diagramma seguente presuppone che l'API di trasporto non sia consapevole della connessione persa, quindi viene rilevata dalla funzionalità keepalive di SignalR e viene generato l'evento ConnectionSlow .

Errore e timeout del server

Timeout e impostazioni keepalive

I valori predefiniti ConnectionTimeout, DisconnectTimeoute KeepAlive sono appropriati per la maggior parte degli scenari, ma possono essere modificati se l'ambiente ha esigenze particolari. Ad esempio, se l'ambiente di rete chiude le connessioni inattive per 5 secondi, potrebbe essere necessario ridurre il valore keepalive.

ConnectionTimeout

Questa impostazione rappresenta la quantità di tempo per lasciare aperta una connessione di trasporto e attendere una risposta prima di chiuderla e aprire una nuova connessione. Il valore predefinito è 110 secondi.

Questa impostazione si applica solo quando la funzionalità keepalive è disabilitata, che in genere si applica solo al trasporto di polling lungo. Il diagramma seguente illustra l'effetto di questa impostazione su una connessione di trasporto di polling prolungata.

Connessione di trasporto di polling lungo

DisconnectTimeout

Questa impostazione rappresenta la quantità di tempo di attesa dopo la perdita di una connessione di trasporto prima di generare l'evento Disconnected . Il valore predefinito è 30 secondi. Quando si imposta DisconnectTimeout, KeepAlive viene impostato automaticamente su 1/3 del DisconnectTimeout valore.

KeepAlive

Questa impostazione rappresenta la quantità di tempo di attesa prima di inviare un pacchetto keepalive su una connessione inattiva. Il valore predefinito è 10 secondi. Questo valore non deve essere maggiore di 1/3 del DisconnectTimeout valore.

Se si desidera impostare sia che DisconnectTimeoutKeepAlive, impostare KeepAlive dopo DisconnectTimeout. In caso contrario, l'impostazione KeepAlive verrà sovrascritta quando DisconnectTimeout viene impostata automaticamente su KeepAlive 1/3 del valore di timeout.

Se si vuole disabilitare la funzionalità keepalive, impostare su KeepAlive Null. La funzionalità Keepalive viene disabilitata automaticamente per il trasporto di polling lungo.

Come modificare le impostazioni di timeout e keepalive

Per modificare i valori predefiniti per queste impostazioni, impostarli nel Application_Start file Global.asax , come illustrato nell'esempio seguente. I valori mostrati nel codice di esempio sono gli stessi dei valori predefiniti.

protected void Application_Start(object sender, EventArgs e)
{
    // Make long polling connections wait a maximum of 110 seconds for a
    // response. When that time expires, trigger a timeout command and
    // make the client reconnect.
    GlobalHost.Configuration.ConnectionTimeout = TimeSpan.FromSeconds(110);
    
    // Wait a maximum of 30 seconds after a transport connection is lost
    // before raising the Disconnected event to terminate the SignalR connection.
    GlobalHost.Configuration.DisconnectTimeout = TimeSpan.FromSeconds(30);
    
    // For transports other than long polling, send a keepalive packet every
    // 10 seconds. 
    // This value must be no more than 1/3 of the DisconnectTimeout value.
    GlobalHost.Configuration.KeepAlive = TimeSpan.FromSeconds(10);
}

Come notificare all'utente le disconnessioni

In alcune applicazioni potrebbe essere necessario visualizzare un messaggio all'utente in caso di problemi di connettività. Sono disponibili diverse opzioni per come e quando eseguire questa operazione. Gli esempi di codice seguenti sono destinati a un client JavaScript che usa il proxy generato.

  • Gestire l'evento connectionSlow per visualizzare un messaggio non appena SignalR è a conoscenza dei problemi di connessione, prima di passare alla modalità di riconnessione.

    $.connection.hub.connectionSlow(function() {
        notifyUserOfConnectionProblem(); // Your function to notify user.
    });
    
  • Gestire l'evento reconnecting per visualizzare un messaggio quando SignalR è a conoscenza di una disconnessione e passa alla modalità di riconnessione.

    $.connection.hub.reconnecting(function() {
        notifyUserOfTryingToReconnect(); // Your function to notify user.
    });
    
  • Gestire l'evento disconnected per visualizzare un messaggio quando si è verificato il timeout di un tentativo di riconnessione. In questo scenario, l'unico modo per ristabilire una connessione con il server consiste nel riavviare la connessione SignalR chiamando il Start metodo , che creerà un nuovo ID connessione. Nell'esempio di codice seguente viene usato un flag per assicurarsi di eseguire la notifica solo dopo un timeout di riconnessione, non dopo una normale fine alla connessione SignalR causata dalla chiamata al Stop metodo .

    var tryingToReconnect = false;
    
    $.connection.hub.reconnecting(function() {
        tryingToReconnect = true;
    });
    
    $.connection.hub.reconnected(function() {
        tryingToReconnect = false;
    });
    
    $.connection.hub.disconnected(function() {
        if(tryingToReconnect) {
            notifyUserOfDisconnect(); // Your function to notify user.
        }
    });
    

Come riconnettersi continuamente

In alcune applicazioni potrebbe essere necessario ristabilire automaticamente una connessione dopo che è stata persa e il tentativo di riconnessione è scaduto. A tale scopo, è possibile chiamare il Start metodo dal Closed gestore eventi (disconnected gestore eventi nei client JavaScript). È possibile attendere un periodo di tempo prima di chiamare Start per evitare di eseguire questa operazione troppo spesso quando il server o la connessione fisica non sono disponibili. L'esempio di codice seguente riguarda un client JavaScript che usa il proxy generato.

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

Un potenziale problema da tenere presente nei client mobili è che i tentativi di riconnessione continui quando il server o la connessione fisica non è disponibile potrebbe causare uno svuotamento della batteria non necessario.

Come disconnettere un client nel codice del server

SignalR versione 1.1.1 non dispone di un'API server predefinita per la disconnessione dei client. In futuro sono previsti piani per l'aggiunta di questa funzionalità. Nella versione corrente di SignalR, il modo più semplice per disconnettere un client dal server consiste nell'implementare un metodo di disconnessione nel client e chiamare tale metodo dal server. L'esempio di codice seguente illustra un metodo di disconnessione per un client JavaScript usando il proxy generato.

var myHubProxy = $.connection.myHub
myHubProxy.client.stopClient = function() {
    $.connection.hub.stop();
};

Avviso

Sicurezza: né questo metodo per disconnettere i client né l'API predefinita proposta risolverà lo scenario di client compromessi che eseguono codice dannoso, poiché i client potrebbero riconnettersi o il codice violato potrebbe rimuovere il stopClient metodo o modificare le operazioni eseguite. La posizione appropriata per implementare la protezione DOS (Denial of Service) con stato non è nel framework o nel livello server, ma piuttosto nell'infrastruttura front-end.