I am using SignalR for displaying onscreen notifications in my web application(built using Asp.net MVC).
My question is How to show notifications to specific set of users eg. Display onscreen notifications to all the users with reader role?. The roles and user associated with roles are defined the database.
I have read it in the documentation where it is mentioned about groups. But i am not sure how to use it.
As you said, one of the ways to go is by using SignalR Groups.
Basically, when you start the connection to the SignalR hub, you can also include that user in a group, based on the type of account (try not to include the user in a group based on a client function call, do it on the server).
So each time the user connects, you can override the OnConnected method and add a user on the appropriate group (in the Groups object are stored ConnectionId strings.
Note - if you are going to scale the application, you will also need to add a backplane for the following reason: the groups and the connection ids are store in the memory of the server. If your application is load balanced, then you have multiple independent instances of the same application, each one with different connections.
The way to go here is to use a SignalR Backplane.
Hope this helps!
Best of luck!
Related
This page in the SignalR docs states:
SignalR sends messages to clients and groups based on a pub/sub model, and the server does not maintain lists of groups or group memberships. This helps maximize scalability, because whenever you add a node to a web farm, any state that SignalR maintains has to be propagated to the new node.
The mentioned scalability benefit of implementing the groups without maintaining state on the server is clear, but how does it work?
Presumably if you send a message to a group, the server must have a list of the connections in each group in order to be able to look them up and send the message to each one. But this says no such list is maintained. Even the statement that it is "based on a pub/sub model" is confusing, since a pub/sub system itself needs to maintain a list of the subscribers in order to know who to publish to.
Does anyone know how this works in SignalR?
I have seen examples that manually keep track of users that are connected but is there a way to determine if a client is connected when using IUserIdProvider?
IUserIdProvider interface allows you to specify how will SignalR assign user id to connection based on request. It doesn't have any direct support for monitoring if user is online.
To monitor online presence, you have to handle OnConnected, OnDisconnected and OnReconnected events in hub and store information about users in some storage (for example static class, database, etc.). Example can be found here: http://www.asp.net/signalr/overview/guide-to-the-api/mapping-users-to-connections#inmemory
The SignalR server hub does not retain a list of groups so I assume that when I send out a broadcast message to a group it is sent to everyone connected to the hub and the clients filter out the message based on their participating groups. If I send a message to a specific group it seems that it is sent down the wire to everyone and can be intercepted by someone not in the specified group who knows how to use a browser debugger. If I want to have a secure broadcast (not even sent over the wire to some clients) I assume I need separate hubs or do I need separate sub domains?
Separate hubs do not sound like a good idea. While you probably can validate users on connect and refuse connections for non-authorized users what if you need a way to create isolated hubs dynamically. If however this functionality is enough for you you can use the Authorize attribute to secure either hubs or hub methods.
For cases where you do need to replicate the same functionality for different groups of users you can use SignalR groups but you need to verify that the user belongs to the group each time he connects. The SignalR documentation contains an example on how to do that verification. Note that everyone can try to connect to your groups and you should validate upon connection and not depend on the fact that you do not call the add method for a certain client.
SignalR only sends to the clients in the group. It's just a design issue that you can't retrieve a list of connections in a group. Groups, as pretty much everything else in SignalR, are subscription based, so the server knows which connections need to receive a message, but it's buried deep in the internals.
I would point you to the relevant server-side code, but don't have time to look it up right now.
It's easy to see in the client-side code though since it's not a lot of code - so you can verify there is no filtering going on there.
Groups also aren't separated per hub.
I just finished one SignalR sample, the well-known Chat sample.
This sample just broadcast a chat message from one client to all the clients. What if we want to send message to only a specific client?
(I guess there should be some ID to identify each client. These IDs should be stored on server when clients subscribe to the server. And server can choose which ID to push message to. )
You have different way to map your user with a connection. You can compare the different ways in this tutorial depending on your requirements.
Another solution is to define 1 group per userId and notify the group when you want to notify a user (link). Be careful, groups are not secured.
Like Daniel describes you can use a group or use the hubcontext to get the context for a specific connection using the connection Id.
var client = context.Clients.Client(connectionId);
There are also several libraries that abstract SignalR, some of these comes with their own way of calling specific users.
I have made a library like this which is based on the Event aggregation pattern. It comes with a API to let you create code that determines which clients should receive a specific event
https://github.com/AndersMalmgren/SignalR.EventAggregatorProxy/wiki/Implement-constraint-handlers
Here is also a blog post I made showing how you can achieve declarative role authorization with my library, maybe it can give you some ideas.
http://andersmalmgren.com/2014/06/12/client-server-event-aggregation-with-role-authorization/
I have a web application, where users will see notifications for their new messages, I want to push the notifications to the users who are already logged in.
I have seen that I can do it using Server Push of PokeIn, I have tried and understood the simple application using it, but I am not getting the ClientID thing.
The ClientId it saves in "OnClientConnected" is a simple integer, so how does it recognizes clients and calls functions on them ?
Also, it is written that it uses a hybrid long polling approach, can somebody please explain me what is this?
I will not be able to implement without having sufficient knowledge of it.
Does saving the ClientID in the database for logged in user and then pushing data using this will do ?
UPDATE:
Even from requests within the same
browser window or tab, the ClientId
received every time on every request
is different, so I had to include the
Handler in my master page and on every
request, I had to map the ClientId
received to the Logged In user, so
that I can send messages to him.
Can't I just map the (ClientId to
LoggedIn UserId) only once on LogIn
and then use that same ClientId to
send him messages ?
ClientID represents the identification key of the specific client view of your application and subject to change on each time.
It helps you to manage and target specific views by keys. On the other hand, you can still use ASP.NET session ids with PokeIn client ids.
The only difference is, if any user opens your application on the different tabs of same browser, each tab will have a unique client id. Actually, this is a great
functionality you may need. On the other hand, PokeIn also notifies you when a client is disconnected (almost instantly)..
You may reach session id by the client id;
CometWorker.GetSessionId(string ClientId)
or client ids for a session id by;
CometWorker.GetClientIdsBySessionId(string sessionId)
Additionally, if you don't want to use client id system (which is very useful), you may choose the "Joint" option. It helps you the send and receive messages from
the client with the name you have defined. (There is a sample for the "Joint" feature in here)
Because PokeIn provides various connection options, you don't have to think about the approach behind it when you work with PokeIn. It simply provides benefits
from the various solutions. More information can be accessible from : "FAQ" and "Advanced Tutorial" (http://www.pokein.com/Help/AdvancedTutorial.aspx)
At last, you don't have to save PokeIn client id to the database. PokeIn manages your server side objects per each client efficiently.
I suggest you to check the samples and tutorials.
As an answer for your update, you are free to use Joint feature of PokeIn when you need shared server side instances for the clients or consistent naming for the clients.