Best practice for reconnecting SignalR 2.0.NET client to server

I am using SignalR 2.0 with the .NET client in a mobile application that needs to handle various types of outages. Sometimes the SignalR client reconnects automatically, and sometimes it needs to be connected directly by calling HubConnection.Start() again.

Since SignalR magically automatically reconnects, I wonder if I am missing a feature or configuration settings?

What is the best way to configure a client that automatically connects?




I saw JavaScript examples that handle the Closed() event and then Connect after n seconds. Is there a recommended approach?

I read the documentation and several articles on the SignalR connection lifetime, but it’s still unclear to me how to handle client reconnection.

+73
c # signalr signalr-hub signalr.client signalr-2
Apr 29 '14 at 20:53 on
source share
5 answers

I finally figured it out. Here is what I learned from the beginning of this question:

Background:. We are creating an iOS application using Xamarin / Monotouch and .NET SignalR 2.0.3. We use SignalR protocols by default - and it looks like it uses SSE instead of web sockets. I'm not sure if you can use web sockets with Xamarin / Monotouch. Everything is hosted on Azure sites.

We needed an application to quickly connect to our SignalR server, but we still had problems when the connection did not reconnect on our own - or reconnecting took exactly 30 seconds (due to the main protocol timeout).

There were three scenarios in which we ended up testing:

Scenario A - Connection at the first boot of the application. It worked flawlessly from day one. The connection is completed in less than .25 seconds, even via 3G mobile connections. (if the radio is already on)

Scenario B - reconnecting to the SignalR server after the application has been idle / closed for 30 seconds. In this case, the SignalR client will eventually reconnect to the server without any special work - but it seems to wait exactly 30 seconds before trying to reconnect. (too slow for our application)

During this 30 second waiting period, we tried to call HubConnection.Start (), which did not affect. And calling HubConnection.Stop () also takes 30 seconds. I found a related error on the SignalR site that seems to be fixed , but we still have the same problem in version 2.0.3.

Scenario C - reconnecting to the SignalR server after the application has been idle / closed for 120 seconds or longer. In this case, the SignalR transport protocol is already disabled, so the client will never automatically reconnect. This explains why the client is sometimes, but not always, rebuilt on its own. The good news is that calling HubConnection.Start () works almost instantly, like script A.

Therefore, it took me a while to understand that the conditions for reconnecting differ depending on whether the application was closed for 30 seconds versus 120 + seconds. Although the SignalR trace logs highlight what is happening with the underlying protocol, I don’t believe that there is a way to handle transport layer events in the code. (The Closed () event fires after 30 seconds in script B, immediately in script C, the State property says “Connected” during these periods of waiting for reconnection, no other relevant events or methods)

Solution: The solution is obvious. We are not waiting for SignalR to do the reconnection magic. Instead, when the application is activated or when the telephone network recovery is restored, we simply clear the events and delete the links to the HubConnection (we cannot dispose of it because it takes 30 seconds, I hope the garbage collection takes care of this) and creates a new instance. Now everything works fine. For some reason, I thought we should reuse a persistent connection and reconnect, not just create a new instance.

+63
May 13 '14 at 23:59
source share

Setting a timer in a disabled event to automatically try reconnecting is the only method I know of.

In javascript, this is done like this:

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

This is the recommended approach in the documentation:

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

+38
May 01 '14 at 11:56
source share

Since the OP is requesting a .NET client (winform implementation below),

 private async Task<bool> ConnectToSignalRServer() { bool connected = false; try { Connection = new HubConnection("server url"); Hub = Connection.CreateHubProxy("MyHub"); await Connection.Start(); //See @Oran Dennison comment on @KingOfHypocrites 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
Jul 24 '17 at 13:58
source share
 Multiple query string self.hubConnection = $.hubConnection(); self.hubConnection.qs = { param1: value, param2: value }; 

from:

Signalr - unable to read query strings on server

0
Feb 16 '19 at 2:59
source share

You can try to call the server method from your android before restoring the start state to prevent the problem of reconnecting magic.

SignalR Hub C #

  public class MyHub : Hub { public void Ping() { //ping for android long polling } } 

In Android

 private final int PING_INTERVAL = 10 * 1000; private boolean isConnected = false; private HubConnection connection; private ClientTransport transport; private HubProxy hubProxy; private Handler handler = new Handler(); private Runnable ping = new Runnable() { @Override public void run() { if (isConnected) { hubProxy.invoke("ping"); handler.postDelayed(ping, PING_INTERVAL); } } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); System.setProperty("http.keepAlive", "false"); ..... ..... connection.connected(new Runnable() { @Override public void run() { System.out.println("Connected"); handler.postDelayed(ping, PING_INTERVAL); }); } 
-2
Jan 24 '15 at 23:18
source share



All Articles