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

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.

Related

How to handle client view synchronization with signal r when a client gets offline for a short period of time and some messages are lost?

I am using SignalR in my web api to provide real-time functionality to my client apps (mobile and web). Everything works ok but there is something that worries me a bit:
The clients get updated when different things happen in the backend. For example, when one of the clients does a CRUD operation on a resource that will be notified by SignalR. But, what happens when something happens on the client, let's say the mobile app, and the device data connection is dropped?.
It could happen that another client has done any action over a resource and when SignalR broadcasts the message it doesn't arrive to that client. So, that client will have an old view sate.
As I have read, it seems that there's no way to know if a meesage has been sent and received ok by all the clients. So, beside checking the network state and doing a full reload of the resource list when this happens is there any way to be sure message synchronization has been accomplished correctly on all the clients?
As you've suggested, ASP NET Core SignalR places the responsibility on the application for managing message buffering if that's required.
If an eventually consistent view is an issue (because order of operations is important, for example) and the full reload proves to be an expensive operation, you could manage some persistent queue of message events as far back as it makes sense to do so (until a full reload would be preferable) and take a page from message buses and event sourcing, with an onus on the client in a "dumb broker/smart consumer"-style approach.
It's not an exact match of your case, but credit where credit is due, there's a well thought out example of handling queuing up SignalR events here: https://stackoverflow.com/a/56984518/13374279 You'd have to adapt that some and give a numerical order to the queued events.
The initial state load and any subsequent events could have an aggregate version attached to them; at any time that the client receives an event from SignalR, it can compare its currently known state against what was received and determine whether it has missed events, be it from a disconnection or a delay in the hub connection starting up after the initial fetch; if the client's version is out of date and within the depth of your queue, you can issue a request to the server to replay the events out to that connection to bring the client back up to sync.
Some reading into immediate consistency vs eventual consistency may be helpful to come up with a plan. Hope this helps!

how to show updated data to the users as fast as possible (not real-time)?

In database some entity is getting updated by some backend process. We want to show this updated value to the user not real-time but as fast as possible on website.
Problems we are facing with these approaches.
Polling :- As we know that there are better techniques then polling like SSE, WebSockets.
SSE :- In SSE the connection open for long time(I search on internet and found that it uses long polling). Which might cause problem when user increases.
WebSockets :- As we need only one way communication(from server to client), SSE is better then this.
Our Solution
We check database on every request of user and update the value.(It is not very good as it will depend upon user next request)
Is it good approach or is there any better way to do this or Am I missing something about SSE(misunderstood something).
Is it fine to use SignalR instead of this all?(is there any long connection issue in it or not?)
Thanks.
It's just up to your requirements what you should use.
Options:
You clients need only the update information, in the case they make a request -> Go your way
If you need a solution with different client types like (Webclient, Winformclient, Androidclient,....) and you have for example different browser types which you should support. Not all browsers support all mechanisme... SignalR was designed to choose automatically the right transport mechanisme according to the mechanisme which a clients supports --> SignalR is an option. (Read more details here: https://www.asp.net/signalr) Has also options that your connection keeps alive.
There are also alternatives like https://pusher.com/ (For short this is only a queue where you can send messages, and also subscribe for messages) But these services are only free until for example some data volume.
You can use event based communication. When ever there is a change(event) in the backend/database, server should send a message to clients.
Your app should register to respective events and refresh the UI when ever there is an update.
We used Socket IO for this usecase, in our apps and it worked well.
Here is the website https://socket.io/

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.

SignalR message lost when client is navigating

I have implemented SignalR successfully.
I am using it to show init conversations between users on the site, so when one wants to chat with someone else, a simple message is sent using SignalR.
This works well, except one situation. If the request is sent the same time as the one supposed to receive it is doing a new page request, like navigating the site, the message is lost.
I can see that the messages expire after 30 seconds in the InProcMessageBus, but I do not think that is the problem, since I am testing on my machine and the page load takes max 1-2 seconds.
So, is this actually by design? Or am I doing it wrong?
Thanks.
This is sort of by design. When a user creates a new connection they get a new clientid by default. This is likely the cause of the issue unless you have defined your own IConnectionIdFactory. If you want to make sure a client always gets the same id you would create your own implementation of this and set it like this:
DependencyResolver.Register(typeof(IConnectionIdFactory), () => new CustomIdFactory());
Extensibility in SignalR - https://github.com/SignalR/SignalR/wiki/Extensibility
Example factory replacement for clientID: http://www.kevgriffin.com/maintaining-signalr-connectionids-across-page-instances/

Resources