SignalR offers a couple of ways to exclude entire sets of connections from a broadcast; here, we see how we can exclude a specific set of connected clients using their ConnectionId
properties.
To demonstrate this feature, we need a slightly more complex sample. Let's consider a case where some of the messages should go unobserved by the specific clients we do not want to target. In such a case, we would need to inform everybody about who else is connected, and provide a way to pick some of those in order to exclude them from the next broadcast. To achieve this, we store a list of all the received connections in a static Hashset
member inside the hub, and we send this set to every connected client when it calls a Subscribe()
method. This set of connections will be used by the client to show a list of identifiers from which the user can select who to exclude when performing the broadcast of the message. To keep the UI simple, we'll let the user exclude just one recipient; however, the code can be easily extended to exclude several of them.
In order to write the code of this recipe, we need to create a new empty web application, which we'll call Recipe11
.
Let's prepare the ground by performing the following steps:
EchoHub
.Startup
and add the Configuration()
method to it, containing a call to app.MapSignalR();
.using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
namespace Recipe11
{
[HubName("echo")]
public class EchoHub : Hub
{
static readonly HashSet<string> connectionIds =
new HashSet<string>();
public void Subscribe()
{
var connectionId = Context.ConnectionId;
connectionIds.UnionWith(
new [] { connectionId });
Clients.All.connections(connectionIds);
}
public void HelloBut(string excludeConnectionId)
{
var msg = string.Format("Welcome {0} at {1:F}!",
Context.ConnectionId,
DateTime.Now);
var allExcept =
Clients.AllExcept(excludeConnectionId);
allExcept.greetings(msg);
}
}
}
What's important here? We need to make sure that we perform the following steps:
Hashset
member to keep a unique list of all the received ConnectionId
values.Subscribe()
method adds the caller's ConnectionId
property to the Hashset
member mentioned in the preceding point, and then broadcasts the complete list to all the connected clients (Clients.All
) calling the connections()
method. Please note that we do not pay any particular attention to potential concurrency problems when accessing the connectionIds
member, but in real-world code, you definitely should.HelloBut()
method, we build a message (msg
) using the current time and ConnectionId
property. When msg
is ready, we reference the Clients
member, inherited from the Hub
type, and we call its AllExcept()
method, which returns a set representing all the currently connected clients except the one specified by passing to it the excludeConnectionId
argument. We store the result in the allExcept
variable.greetings()
method on the allExcept
variable.The client will have to host a button to send the message and a list where it can show the available ConnectionId
values. The user will pick one of them and the client will pass it to the HelloBut()
call to exclude it from the subsequent broadcast.
The following sample code, like many others in the future, has to do some Document Object Model (DOM) manipulation mixed with logic specific to the sample itself. We perform DOM manipulation using jQuery, and we try to keep it at a minimum to avoid distracting you from the relevant portions. Nevertheless, some of it is necessary; therefore, please pay more attention to what's actually related to SignalR and consider the rest as just plumping code that we need in order to have things working.
Let's build our client code in an HTML page called index.html
. Add the following code to this page:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Recipe11</title> <script src="Scripts/jquery-2.1.0.js"></script> <script src="Scripts/jquery.signalR-2.0.2.js"></script> <script src="/signalr/hubs"></script> <script> $(function () { var hub = $.connection.echo, connectionId; hub.client.connections = function (ids) { $('#ids').empty(); for (var i = 0, l = ids.length; i < l; i++) { var id = ids[i]; if (id !== connectionId) { $('#ids').append( $('<option/>') .attr('value', id) .html(id)); } } if (ids.length) $('#sender').show(); }; hub.client.greetings = function (message) { $('#messages').append($('<li/>').html(message)); }; $.connection.hub .start() .done(function () { connectionId = $.connection.hub.id; $('#id').html(connectionId); hub.server.subscribe(); $('#send') .click(function () { hub.server.helloBut($('#ids').val()); }); }); }); </script> </head> <body> <p id="id"></p> <div id="sender" style="display: none"> <button id="send">Send to all but</button> <select id="ids"></select> </div> <ul id="messages"></ul> </body> </html>
At the beginning, we prepare the hub.client
member, adding the callback methods that the Hub will invoke (connections()
and greetings()
); each one of them will manipulate the content of the page accordingly. Then, we start the connection, and when done, we proceed with the following:
connectionId = $.connection.hub.id
) used to filter out that value from the list of available connections we built inside the connections()
callbacksubscribe()
server-side methodclick
event of the send
button to a method, which will perform the helloBut()
calls, passing to it the connection identifier to be excluded from the broadcast and picked from the selected one in the listWe can now open index.html
multiple times in different browser windows or tabs, and then click on the Say Hello to all but button. Each time we click on the button, all the browser windows will receive the same message except the one whose identifier has been selected to be excluded from the broadcast. The Clients.AllExcept()
method is effectively giving us access to the whole set of active connections, excluding the specified ones (in this case, we always specify just one exclusion, but they could be many), and it gives us a way to broadcast method calls to all of them at once.
3.140.242.165