Broadcasting to all clients except the specified ones

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.

Getting ready

In order to write the code of this recipe, we need to create a new empty web application, which we'll call Recipe11.

How to do it…

Let's prepare the ground by performing the following steps:

  1. We add a Hub called EchoHub.
  2. We then need the OWIN Startup bootstrap class. We name it Startup and add the Configuration() method to it, containing a call to app.MapSignalR();.
  3. The Hub should contain the following code:
    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:

  • The class contains a static Hashset member to keep a unique list of all the received ConnectionId values.
  • The 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.
  • Inside the 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.
  • We finally call the 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.

Note

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:

  • We store the ID of the current connection in a variable (connectionId = $.connection.hub.id) used to filter out that value from the list of available connections we built inside the connections() callback
  • We call the subscribe() server-side method
  • We finally hook the click 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 list

We 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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.140.242.165