"
 
 
 
ASP.NET (snapshot 2017) Microsoft documentation and samples

Understanding and Handling Connection Lifetime Events in SignalR

by Patrick Fletcher, Tom Dykstra

This article provides an overview of the SignalR connection, reconnection, and disconnection events that you can handle, and timeout and keepalive settings that you can configure.

The article assumes you already have some knowledge of SignalR and connection lifetime events. For an introduction to SignalR, see Introduction to SignalR. For lists of connection lifetime events, see the following resources:

Software versions used in this topic

Previous versions of this topic

For information about earlier versions of SignalR, see SignalR Older Versions.

Questions and comments

Please leave feedback on how you liked this tutorial and what we could improve in the comments at the bottom of the page. If you have questions that are not directly related to the tutorial, you can post them to the ASP.NET SignalR forum or StackOverflow.com.

Overview

This article contains the following sections:

Links to API Reference topics are to the .NET 4.5 version of the API. If you’re using .NET 4, see the .NET 4 version of the API topics.

Connection lifetime terminology and scenarios

The OnReconnected event handler in a SignalR Hub can execute directly after OnConnected but not after OnDisconnected for a given client. The reason you can have a reconnection without a disconnection is that there are several ways in which the word “connection” is used in SignalR.

SignalR connections, transport connections, and physical connections

This article will differentiate between SignalR connections, transport connections, and physical connections:

In the following diagram, the SignalR connection is represented by the Hubs API and PersistentConnection API SignalR layer, the transport connection is represented by the Transports layer, and the physical connection is represented by the lines between the server and the clients.

SignalR architecture diagram
SignalR architecture diagram

When you call the Start method in a SignalR client, you are providing SignalR client code with all the information it needs in order to establish a physical connection to a server. SignalR client code uses this information to make an HTTP request and establish a physical connection that uses one of the four transport methods. If the transport connection fails or the server fails, the SignalR connection doesn’t go away immediately because the client still has the information it needs to automatically re-establish a new transport connection to the same SignalR URL. In this scenario, no intervention from the user application is involved, and when the SignalR client code establishes a new transport connection, it does not start a new SignalR connection. The continuity of the SignalR connection is reflected in the fact that the connection ID, which is created when you call the Start method, does not change.

The OnReconnected event handler on the Hub executes when a transport connection is automatically re-established after having been lost. The OnDisconnected event handler executes at the end of a SignalR connection. A SignalR connection can end in any of the following ways:

When there are no connection problems, and the user application ends the SignalR connection by calling the Stop method, the SignalR connection and the transport connection begin and end at about the same time. The following sections describe in more detail the other scenarios.

Transport disconnection scenarios

Physical connections might be slow or there might be interruptions in connectivity. Depending on factors such as the length of the interruption, the transport connection might be dropped. SignalR then tries to re-establish the transport connection. Sometimes the transport connection API detects the interruption and drops the transport connection, and SignalR finds out immediately that the connection is lost. In other scenarios, neither the transport connection API nor SignalR becomes aware immediately that connectivity has been lost. For all transports except long polling, the SignalR client uses a function called keepalive to check for loss of connectivity that the transport API is unable to detect. For information about long polling connections, see Timeout and keepalive settings later in this topic.

When a connection is inactive, periodically the server sends a keepalive packet to the client. As of the date this article is being written, the default frequency is every 10 seconds. By listening for these packets, clients can tell if there is a connection problem. If a keepalive packet is not received when expected, after a short time the client assumes that there are connection problems such as slowness or interruptions. If the keepalive is still not received after a longer time, the client assumes that the connection has been dropped, and it begins trying to reconnect.

The following diagram illustrates the client and server events that are raised in a typical scenario when there are problems with the physical connection that aren’t immediately recognized by the transport API. The diagram applies to the following circumstances:

Transport disconnections
Transport disconnections

If the client goes into reconnecting mode but can’t establish a transport connection within the disconnect timeout limit, the server terminates the SignalR connection. When that happens, the server executes the Hub’s OnDisconnected method and queues up a disconnect message to send to the client in case the client manages to connect later. If the client then does reconnect, it receives the disconnect command and calls the Stop method. In this scenario, OnReconnected is not executed when the client reconnects, and OnDisconnected is not executed when the client calls Stop. The following diagram illustrates this scenario.

Transport disruptions - server timeout
Transport disruptions - server timeout

The SignalR connection lifetime events that may be raised on the client are the following:

Transport connection interruptions that are not detected by the transport API and don’t delay the reception of keepalive pings from the server for longer than the keepalive timeout warning period might not cause any connection lifetime events to be raised.

Some network environments deliberately close idle connections, and another function of the keepalive packets is to help prevent this by letting these networks know that a SignalR connection is in use. In extreme cases the default frequency of keepalive pings might not be enough to prevent closed connections. In that case you can configure keepalive pings to be sent more often. For more information, see Timeout and keepalive settings later in this topic.

[!NOTE]

Important: The sequence of events described here is not guaranteed. SignalR makes every attempt to raise connection lifetime events in a predictable manner according to this scheme, but there are many variations of network events and many ways in which underlying communications frameworks such as transport APIs handle them. For example, the Reconnected event might not be raised when the client reconnects, or the OnConnected handler on the server might run when the attempt to establish a connection is unsuccessful. This topic describes only the effects that would normally be produced by certain typical circumstances.

Client disconnection scenarios

In a browser client, the SignalR client code that maintains a SignalR connection runs in the JavaScript context of a web page. That’s why the SignalR connection has to end when you navigate from one page to another, and that’s why you have multiple connections with multiple connection IDs if you connect from multiple browser windows or tabs. When the user closes a browser window or tab, or navigates to a new page or refreshes the page, the SignalR connection immediately ends because SignalR client code handles that browser event for you and calls the Stop method. In these scenarios, or in any client platform when your application calls the Stop method, the OnDisconnected event handler executes immediately on the server and the client raises the Closed event (the event is named disconnected in JavaScript).

If a client application or the computer that it’s running on crashes or goes to sleep (for example, when the user closes the laptop), the server is not informed about what happened. As far as the server knows, the loss of the client might be due to connectivity interruption and the client might be trying to reconnect. Therefore, in these scenarios the server waits to give the client a chance to reconnect, and OnDisconnected does not execute until the disconnect timeout period expires (about 30 seconds by default). The following diagram illustrates this scenario.

Client computer failure
Client computer failure

Server disconnection scenarios

When a server goes offline – it reboots, fails, the app domain recycles, etc. – the result might be similar to a lost connection, or the transport API and SignalR might know immediately that the server is gone, and SignalR might begin trying to reconnect without raising the ConnectionSlow event. If the client goes into reconnecting mode, and if the server recovers or restarts or a new server is brought online before the disconnect timeout period expires, the client will reconnect to the restored or new server. In that case, the SignalR connection continues on the client and the Reconnected event is raised. On the first server, OnDisconnected is never executed, and on the new server, OnReconnected is executed although OnConnected was never executed for that client on that server before. (The effect is the same if the client reconnects to the same server after a reboot or app domain recycle, because when the server restarts it has no memory of prior connection activity.) The following diagram assumes that the transport API becomes aware of the lost connection immediately, so the ConnectionSlow event is not raised.

Server failure and reconnection
Server failure and reconnection

If a server does not become available within the disconnect timeout period, the SignalR connection ends. In this scenario, the Closed event (disconnected in JavaScript clients) is raised on the client but OnDisconnected is never called on the server. The following diagram assumes that the transport API does not become aware of the lost connection, so it is detected by SignalR keepalive functionality and the ConnectionSlow event is raised.

Server failure and timeout
Server failure and timeout

Timeout and keepalive settings

The default ConnectionTimeout, DisconnectTimeout, and KeepAlive values are appropriate for most scenarios but can be changed if your environment has special needs. For example, if your network environment closes connections that are idle for 5 seconds, you might have to decrease the keepalive value.

ConnectionTimeout

This setting represents the amount of time to leave a transport connection open and waiting for a response before closing it and opening a new connection. The default value is 110 seconds.

This setting applies only when keepalive functionality is disabled, which normally applies only to the long polling transport. The following diagram illustrates the effect of this setting on a long polling transport connection.

Long polling transport connection
Long polling transport connection

DisconnectTimeout

This setting represents the amount of time to wait after a transport connection is lost before raising the Disconnected event. The default value is 30 seconds. When you set DisconnectTimeout, KeepAlive is automatically set to 1/3 of the DisconnectTimeout value.

KeepAlive

This setting represents the amount of time to wait before sending a keepalive packet over an idle connection. The default value is 10 seconds. This value must not be more than 1/3 of the DisconnectTimeout value.

If you want to set both DisconnectTimeout and KeepAlive, set KeepAlive after DisconnectTimeout. Otherwise your KeepAlive setting will be overwritten when DisconnectTimeout automatically sets KeepAlive to 1/3 of the timeout value.

If you want to disable keepalive functionality, set KeepAlive to null. Keepalive functionality is automatically disabled for the long polling transport.

How to change timeout and keepalive settings

To change the default values for these settings, set them in Application_Start in your Global.asax file, as shown in the following example. The values shown in the sample code are the same as the default values.

[!code-csharpMain]

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

How to notify the user about disconnections

In some applications you might want to display a message to the user when there are connectivity problems. You have several options for how and when to do this. The following code samples are for a JavaScript client using the generated proxy.

How to continuously reconnect

In some applications you might want to automatically re-establish a connection after it has been lost and the attempt to reconnect has timed out. To do that, you can call the Start method from your Closed event handler (disconnected event handler on JavaScript clients). You might want to wait a period of time before calling Start in order to avoid doing this too frequently when the server or the physical connection are unavailable. The following code sample is for a JavaScript client using the generated proxy.

[!code-javascriptMain]

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

A potential problem to be aware of in mobile clients is that continuous reconnection attempts when the server or physical connection isn’t available could cause unnecessary battery drain.

How to disconnect a client in server code

SignalR version 2 does not have a built-in server API for disconnecting clients. There are plans for adding this functionality in the future. In the current SignalR release, the simplest way to disconnect a client from the server is to implement a disconnect method on the client and call that method from the server. The following code sample shows a disconnect method for a JavaScript client using the generated proxy.

[!code-javascriptMain]

   1:  var myHubProxy = $.connection.myHub
   2:  myHubProxy.client.stopClient = function() {
   3:      $.connection.hub.stop();
   4:  };

[!WARNING] Security - Neither this method for disconnecting clients nor the proposed built-in API will address the scenario of hacked clients that are running malicious code, since the clients could reconnect or the hacked code might remove the stopClient method or change what it does. The appropriate place to implement stateful denial-of-service (DOS) protection is not in the framework or the server layer, but rather in front-end infrastructure.

## Detecting the reason for a disconnection

SignalR 2.1 adds an overload to the server OnDisconnect event that indicates if the client deliberately disconnected rather than timing out. The StopCalled parameter is true if the client explicitly closed the connection. In JavaScript, if a server error led the client to disconnect, the error information will be passed to the client as $.connection.hub.lastError.

C# server code: stopCalled parameter

[!code-csharpMain]

   1:  public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled)
   2:  {
   3:      if (stopCalled)
   4:      {
   5:          Console.WriteLine(String.Format("Client {0} explicitly closed the connection.", Context.ConnectionId));
   6:      }
   7:      else
   8:      {
   9:          Console.WriteLine(String.Format("Client {0} timed out .", Context.ConnectionId));
  10:      }
  11:              
  12:      return base.OnDisconnected(stopCalled);
  13:  }

JavaScript client code: accessing lastError in the disconnect event.

[!code-javascriptMain]

   1:  $.connection.hub.disconnected(function () {
   2:      if ($.connection.hub.lastError) 
   3:          { alert("Disconnected. Reason: " +  $.connection.hub.lastError.message); }
   4:  });





Comments ( )
<00>  <01>  <02>  <03>  <04>  <05>  <06>  <07>  <08>  <09>  <10>  <11>  <12>  <13>  <14>  <15>  <16>  <17>  <18>  <19>  <20>  <21>  <22>  <23
Link to this page: //www.vb-net.com/AspNet-DocAndSamples-2017/aspnet/signalr/overview/guide-to-the-api/handling-connection-lifetime-events.htm
<SITEMAP>  <MVC>  <ASP>  <NET>  <DATA>  <KIOSK>  <FLEX>  <SQL>  <NOTES>  <LINUX>  <MONO>  <FREEWARE>  <DOCS>  <ENG>  <CHAT ME>  <ABOUT ME>  < THANKS ME>