Search code examples
c#asp.net-mvc-3signalrsignalr-hub

Signalr - Join multiple groups


Edit: David Fowler requested for the full code to attempt to replicate the problem. Here is the full code

In addition to the code reproduced here, I have also uploaded a complete Visual Studio 2010 solution to the following URL

http://www.sendspace.com/file/lfeurf (URL has now expired and no longer works)

Please feel free to download and test it.

Here are my findings

  1. Adding only one group in the Hub code will make the application work fine with no problems
  2. Adding 2 groups will either stop signalr from working or will work in one direction only. ie: the message will be transmitted from browser 1 to browser 2 but will not be transmitted from browser 2 to browser 1

Original question: I am using Signalr 1.0.0-rc1 in a MVC3 website. My clients sometimes need to belong to multiple groups. Here is the code in my Hub and client side javascript

Client side javascript and HTML

<script type="text/javascript">
    //start signalr
    var message = $.connection.messageHub;

    // Declare a function on the message hub so the server can invoke it          
    message.client.send = function (message) {
        alert(message);
    }

    // Start the connection and join groups
    $.connection.hub.start();

    //bind click event of button to invoke send function on server
    $(document).ready(function () {
        $("#target").click(function () {
            message.server.send("Hello from signalr");
        });
    });
</script>

<button id="target">Click to send message to other clients</button>

Server side Hub

public class MessageHub: Hub
    {
        public Task AddGroups()
        {
            //add 1st group
            Groups.Add(Context.ConnectionId, "foo");
            //add 2nd group
            return Groups.Add(Context.ConnectionId, "foobar");
        }

        //this method will be called from the client
        public void Send(string message)
        {
            Clients.OthersInGroup("foobar").send(message);
        }

        //automatically join groups when client first connects
        public override Task OnConnected()
        {
            return AddGroups();
        }

        //rejoin groups if client disconnects and then reconnects
        public override Task OnReconnected()
        {
            return AddGroups();
        }

    }

The above code should add two groups to each client when they first connect but it does not work. I stepped through the C# code using a debugger and no errors are being thrown. I also dont see any javascript errors using Chrome's console but the Send function is not being called on the clients. I then changed the AddGroups() method to add only one group as shown below

public Task AddGroups()
   {
        //dont add first group
        //Groups.Add(Context.ConnectionId, "foo");
        //add only second group
        return Groups.Add(Context.ConnectionId, "foobar");
   }

Now my application works perfectly. How do I add a second group? It looks like I have misunderstood joining multiple groups. Could anyone show me the right way to do it?


Solution

  • Your issues seems to be that return Groups.Add(Context.ConnectionId, "foobar"); in AddToGroups is timing out after 5 seconds. The Task returned from Groups.Add doesn't complete until SignalR verifies that the client with the specified connectionId has received the add to group command. If this doesn't happen within 5 seconds the Task is cancelled. It appears there is currently a bug preventing waiting on Groups.Add inside of OnConnected and OnReconnected.

    Since you are returning the cancelled Task from OnConnected and OnReconnected, the server is preventing the client from establishing a connection.

    A workaround is to ignore the Task returned from Groups.Add like so:

    public class MessageHub: Hub
    {
        public Task AddGroups()
        {
            //add 1st group
            Groups.Add(Context.ConnectionId, "foo");
            //add 2nd group
            return Groups.Add(Context.ConnectionId, "foobar");
        }
    
        //this method will be called from the client
        public void Send(string message)
        {
            Clients.OthersInGroup("foobar").send(message);
        }
    
        //automatically join groups when client first connects
        public override Task OnConnected()
        {
            AddGroups();
            return base.OnConnected();
        }
    
        //rejoin groups if client disconnects and then reconnects
        public override Task OnReconnected()
        {
            AddGroups();
            return base.OnReconnected();
        }
    
    }