SignalR: Is it necessary to remove the connection id from group OnDisconnect()? - signalr

The tutorials only covered adding a connection ID to the group on OnConnected(), but what about cleaning it up on OnDisconnect()?
After a permanent loss of connectivity, a client is given a new connection ID. What happens to its old connection ID in the group list? Is it automatically cleaned up? or is it scalable enough that I don't have to worry about it?

According to the statement here, you don't need to remove connections from groups:
You should not manually remove the user from the group when the user
disconnects. This action is automatically performed by the SignalR
framework.
When a connection subscribes to a topic (which happens when you add the connection to a group), it receives a disposable which will remove the subscription when disposed (which means the connection isn't in the group anymore). This is triggered when a connection disconnects and is removed.

Related

How do I disconnect from SignalR when the user logs out?

when a user logs off my application (setting enc_token to null) how do I disable signalR (using angular)?
I tried
abp.signalr = null;
The issue is, if a user logs off then back on again, 2 connections are then made. What is the correct way to stop it?
SignalR version 2 does not have a built-in server API for disconnecting clients. Here's the docs stating it.
Essentially, you are dealing with a situation where the handling of connections, reconnects, etc. are not aligning.
You could assign your logged in user to a group and just send data based on group. This way it won't matter if you have multiple connections. When they are disconnected, remove them from the group using OnDisconnect(). Check out the section on Working with Groups at the same link.

Cursor payload is too big compared to the useful payload

Steps to reproduce
The logic of the application assumes that there are number of data sources on the server which are handled by groups.
If client wants to subscribe to the specific data source, it calls:
myhub.Subscribe(dataSourceId);
On the server side, we just add the client to the specific group:
await Groups.Add(Context.ConnectionId, dataSourceId.ToString());
Then all the messages are sent with huge cursor payload. And the most important part, the size of it grows with every subscription.
Am I doing something wrong?
Update
Similar: SignalR and large number of groups
Unfortunately this is how cursors work. Cursor contains references to all topics the connection is subscribed to and each group is a separate topic. Besides the cursor getting bigger there is one more limitation to using many groups. The more groups the client is a member of the bigger the groups token. The groups token is sent back to the server when the client is reconnecting and if it gets too big it may exceed the URL size limit causing reconnect failures.

SignalR: How does server correctly subscribe to a group when connection is established

I have look at the several places, but still can not find clear instructions on how groups should be used. I am using a groups for filtering (delivering the message just to subset of clients).
I would like to join a client to the group on the server side in OnConnected event. Client does not need to know to which groups it belongs.
Questions:
Should I also override the OnReconnected event?
Should I return the Task returned from GroupManager.Add as the result of OnConnected event? If I would like to join multiple groups, I probably need to create a combined task. Right?
3- Why does the server (see GroupManager.Add implementation) sends the AddToGroup command the client? Is there a way to work around this? Maybe by using Client.AllExcept(...) and manually handling group membership on the server (yuck!)?
I am using the latest version of SignalR (1.0.0.1)
You do not need to override OnReconnected. When a client reconnects it will rejoin all groups it was previously in.
You don't have to, but if you try sending to that group within the OnConnected (if you choose to not return the group addition task) you will need to wait until the task completes.
You do not want to work around this, one of the reasons its necessary is because of #2 (the client needs to know what groups it is in). If you want to authenticate groups for reconnect you can always create a hub pipeline module and override the BuildRejoiningGroups function to perform your own verification.
Response to Comments
Comment 1: Yes
Comment 2: You must return a task otherwise nothing will complete (this is by design). If you do not know what to return you can always return base.OnConnected().
When you call GroupManager.Add it returns a task that represents when the connection is in the desired group. Once joining the group the client then gets notified that its now in a new group via a token. The token will then allow the client to rejoin the group if it has to reconnect due to loss of connectivity.

SignalR Disconections

I am using Signalr in an application I'm writing and storing all the user connections in a concurrent dictionary
ConcurrentDictionary<string, User> _users = new ConcurrentDictionary<string, User>();
e.g.
https://github.com/SignalR/SignalR/blob/master/samples/SignalR.Hosting.AspNet.Samples/Hubs/ShapeShare/ShapeShare.cs
I have implemented the IDisconnect interface on my Hub and I'm removing users from the dictionary when they disconnect
I am wondering how reliable the Disconnect method really is?
Does it capture all the different ways that a user could diconnect?
I dont want the dictionary to grow and grow indefinitely
I was thinking of maybe having a timer to periodically traverse the dictionary and remove users who havent had any recent activity
Is this necessary? Can I rely on the disconnect method?
Check out https://github.com/SignalR/SignalR/wiki/Configuring-SignalR , there are settings for :
DisconnectTimeout
KeepAlive
& Heatbeat interval
These could all be applied to help in maintaining your dictionary.
In my experience a graceful disconnect seems to work perfectly on signalR (still problems with win-apps) , if it ungracefully disconnects in a few minutes the connection will timeout and the disconnect method will fire and remove it from your dictionary like Drew said.
You could create a method that sends a message to all clients and log the returned connection ID and then remove any entries that are old, but in practice the disconnect method does work/work itself out, I would only implement the heartbeat interval if you really need to keep a very close eye on the connections.
If it doesn't fire it's a bug and you should report an issue to the SignalR project on GitHub. Here's a list of open issues with Disconnects at this time.
Be aware that diff. transports have diff. disconnect detection logic and so, depending on which transport the user is using, you will see diff. patterns of when the Disconnect fires, but it SHOULD fire eventually for all transports.

SignalR How is a duplicate Connection Id handled?

I have created my own IConnectionIdGenerator implementation which for simpicty in my webforms application names the client connection Id by the EmailAddress.ToLower() of the logged in authenticated user (if that’s not available then it defaults back a guid).
Calling the client from my page code behind all works fine.
hubContext.Clients[LoggedInUser.EmailAddress.ToLower()].updateProgress(i)
However it seems that if I open another browser or tab with the same logged in user both the foreverframe connection on both windows keeps giving a 301 result then a 200 result alternating and repeating.
I assumed that assigning the same connection Id would just give me an easy way to make sure messages correctly go to the correct user of the system no matter where they connected.
Do they always have to be unique and will I have to build another layer to manage connections to logged-in user accounts or am I missing a trick here?
Connection ids have to be unique. If you don't make them unique then one will kick the other connection offline. Internally we use the connection id as a unique identifier for a connection and we disconnect dupes.
If you get repeated 301 responses it's likely because you have a folder in your app called signalr, and it isn't directly related to sharing connection ids.
I recently tried to do the same and experienced the same problems, so my conclusion is that the connection id must be unique, otherwise everything starts to fail with repeated 301 and 200 responses.
What I did to workaround this problem was to use the default GUID connection id and instead add the connection to a group which is identified by my own id (email address in your case) after starting the connection.
This way I can call Clients[emailAddress].doSomething() and it broadcasts to all open tabs of this user.
Yes thats perfect, I came to a simlar conclusion.
I also trying to think of a way to make client broadcast messages to the same email address group unique to the current url (so a progress bar on one page does not also update a progress bar on another)
I will either make extend the group id to be something like emailAddress + currentURL so its just a combination of the two strings. However that would make any global site broadcasts (to all urls) difficult to do unless there is a way of getting the groups collection and parsing out the email addresses and sending the message to each email address + url combination.
It may be better if I just tag on some client side check and send a progress bar Id as a parameter that is unique to the progress bar on the page that is ment to be updated.

Resources