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

SignalR: How to stop creating new connection on page reload


Hi i am developing a chat application along with some other pages in my application. once i login i am maintaining the session of the user. My main intention is that user should get notification whenever another user connects to server.

The problem that i am facing is whenever i navigate to some other page in my application the connection is lost. How to stop this behaviour and continue the connection until user logs out.

I am using SignalR 2.0 in ASP.NET MVC4 project, any help??


Solution

  • Each connection only has a lifecycle for the duration of the time the user spends on a given page. When they navigate to another page, a new connection is established. Also, if a user has more than one tab or browser window open, they will have multiple connection Ids. I don't think you want to try to persist the connection Id beyond it's intended lifecycle.

    In a similar scenario that I work on, we store the connectionIds OnConnect and delete them OnDisconnect. When a message needs to be sent to a given user, we send it to all of their connectionIds. This ensures that the message will be delivered to all tabs/windows.

    EDIT 1 the following is in response to @Saurabh's comments:

    Consider what the scope of the Hub is, and that of your other classes and the client. The Hub is there to facilitate communications between the browser and the server. While it's possible to do a lot of work within the hub, I think it's best to move most of the scope outside of communictions to other places.

    The client knows that it just reloaded a page, so it's a good candidate for making the decision that this is a reconnect event.

    _chatHub.server.reJoinRooms();
    

    Then the Hub can query the user's rooms, by UserId, rather than ConnectionId.

    public Task ReJoinRooms()
    {
    // get the user's rooms from your repository
    // optionally get the user's connectionIds from your repository
    // Clients.Caller.onJoinRooms(rooms);
    // or Clients.Clients(_connectionIds).onJoinRooms(rooms);
    }
    

    Then the client can decide whether or not to take action:

    $chatModule.client.onJoinRooms = function (rooms) {
       for (var i in rooms) {
               var _room = rooms[i];
               // if I'm not already in this room, add it to my rooms
               console.log('joining room', _room)
           }
    }
    

    You could skin this many different ways. The client could own the scope of remembering rooms, instead of a server-side repository, too.

    EDIT 2

    If the number of groups/rooms that a user belongs to is ever-increasing, the above example may not scale up very well.

    In that case, each user could join personal feed(s) instead (i.e. join a feed named for the user's GUID). We would keep track of each user that is affiliated with a group. When a message is sent to that group, we would iterate over those user's and publish a message to each feed.