Long ago, I blogged about integrated SignalR with AngularJS. An interesting behavior that I didn’t touch on was limiting messages being sent to specific clients. This is pretty easy to accomplish.
SignalR, by its very design, will send all messages to any clients that have started a connection when “context.Clients.All” is used to send messages. This occurs even if the client hasn’t explicitly subscribed to an event.
Why does this occur? It’s because all hubs are routed through a single connection at the client. That is to say, when a connection is started via $.connection.hub.start, the client is going to get all messages that are sent to all clients. JavaScript only provides a mechanism to subscriptions to the messages through events.
This can create a very chatty bit of traffic when there are lots of hubs and lots of messages being sent. It could very well be that you’re only interested in a handful of those messages at any given time, though.
Using groups, messages can be limited in a semi-global manner rather than discrete client messages. Take, for example, this NotificationHub.
public class NotificationHub : Hub { private string _group = "notification-group"; public void SendMessage(string message) { var context = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>(); context.Clients.Group(_group).notificationMessage(message); } public void GroupSubscribe() { this.Groups.Add(this.Context.ConnectionId, _group); } public void GroupUnsubscribe() { this.Groups.Remove(this.Context.ConnectionId, _group); } }
I’ve made this hub such that it only sends messages to a specific group and clients must subscribe to that group. Without subscribing to the group, the messages from this hub will not be sent to the a client.
If you’ll recall the “signalrService” from the previous blog post, I only needed to add a method to allow subscribe to the group for a particular hub. Calling this method will in turn call the hub’s “GroupSubscribe” method.
var groupSubscribe = function (name) { var messageHub = findHubByName(name); messageHub.hub.server.groupSubscribe(); };
Within the Angular controller that will consume these messages, the event subscription and group subscription both must be called:
signalrService.groupSubscribe('notificationHub'); signalrService.subscribe('notificationHub', 'notificationMessage');
After adding and using the groupSubscribe method, the desired effect is achieved. Only messages for the groups in which we are members are sent to the browser. This can be verified by turning on SignalR logging.
By the way, I used my TaskRepeater to verify the message flow by sending messages rapidly.
TaskRepeater.Interval(TimeSpan.FromMilliseconds(500), () => { try { var hubManager = new DefaultHubManager(GlobalHost.DependencyResolver); var hub = hubManager.ResolveHub("notificationHub") as NotificationHub; hub.SendMessage("hello hello hello hello hello hello hello hello hello hello hello"); } catch { } }, new System.Threading.CancellationToken(), true);