I recently had the need to keep a SignalR connection even if the page would reload. As far as I know, this cannot be done out of the box, either with hubs or persistent connections. I looked it up, but could find no solid solution, so here is my solution!
As you can see, this function first checks to see if the session id was created, by inspecting the sessionStorage object, and, if not, sets it.
Next, we need to have SignalR pass this session id on every request to the server. For that, I used $.connection.hub.qs, the query string parameters object:
Moving on to the server-side, I used a static collection to store, for each session id, each SignalR connection id associated with it – one for each page request. The reasoning is, each page reload generates a new SignalR connection id, but the session id is always kept:
As you can see, both on OnConnected as in OnReconnected, I add the current connection id to the collection (ConcurrentDictionary<TKey, TValue> to allow multiple concurrent accesses) indexed by the session id that I sent in the SignalR query string. Then, I have a method that looks in the collection for all connection id entries that are siblings of a given connection id. If more than one exists, it means that the page has reloaded, otherwise, there will be a one-to-one match between connection ids and session ids.
The final step is to broadcast a message to all the sibling connection ids – a waste of time because only one is still possibly active, but since we have no way of knowing, it has to be this way:
This Web API action method will get the context for our hub (NotificationHub), look up all of the sibling connection ids for the passed one, and then broadcast a message to all clients identified by these connection ids. It’s a way to send messages from outside of a page into a hub’s clients
Problems with this approach:
All tabs will get the same session id, but that also happens with cookies;
Although unlikely, it may be possible for two clients to get the same session id, which I implemented as the current timestamp; an easy fix would be, for example, to use a pseudo-GUID, the server-side session id, or even the SignalR connection id;
If the page reloads several times, there will be several connection id entries for the same session id – which will be kept throughout all reloads; no easy way to get around this, except possibly using some cache with expiration mechanism.
And that’s it. Enjoy!