Connect signal hub from multiple pages

In my application, I need to connect to a signalR hub from one page, and then I want to redirect to another page, and still use the same signalR connection to communicate with the server. If I connect to the signalR hub from one page, Page1 and redirect to another page, the chat objects from Page1 are invalid ...

***var chat = $.connection.chatHub;
// Start the connection.
$.connection.hub.start().done(function () {});***

      

I also tried to store the chat variable in sessionStorage on the page that creates the signalR hub connection and then restore it on another page, but failed ...

Is there a way to connect to the signalR hub from Page1 and use the same connection from another page (use the same connection id)?

+3


source to share


1 answer


So, if I understand your question correctly, you want the same user to connect to your signal hub when they go to the anther page. If so, then I came up with a solution that works very well for me.

Here are the methods of the hub class:

private static List<UserViewModel> ConnectedUsers = new List<UserViewModel>();


/*
 * The 4 methods below handle user connection/disconnection
 */
public void Connect(string UserId)
{
    if(ConnectedUsers.Count(x => x.ConnectionId.Equals(Context.ConnectionId)) == 0)
    {
        if(ConnectedUsers.Count(x => x.UserId.Equals(UserId)) == 0)
        {
            var ConnectionId = Context.ConnectionId;
            ConnectedUsers.Add(new UserViewModel(UserId, ConnectionId));
        }
        else
        {
            SetConnection(UserId);
        }
    }
}

//This will be called when a user disconnects
public void Disconnect()
{
    var item = ConnectedUsers.FirstOrDefault(x => x.ConnectionId.Equals(Context.ConnectionId));
    if(item != null)
    {
        ConnectedUsers.Remove(item);
        //Update 
    }
}

//This method will handle when a user is assigned another ConnectionId
public void SetConnection(string UserId)
{
    if (ConnectedUsers.Count(x => x.UserId.Equals(UserId)) != 0)
    {
        UserViewModel Existing = ConnectedUsers.FirstOrDefault(x => x.UserId.Equals(UserId));
        ConnectedUsers.Remove(Existing);
        Existing.ConnectionId = Context.ConnectionId;
        ConnectedUsers.Add(Existing);
    }
    else
    {
        Connect(UserId);
    }
}

/*
This gets called every time a user navigates to another page, 
but if they stay on the site then their connection will be reset 
and if they go off site then their connection will be terminated and reset
the next time the log back into the site
*/
public override Task OnDisconnected(bool stopCalled)
{
    Disconnect();
    return base.OnDisconnected(stopCalled);
}

      

In your application, you need to assign your users a unique and static ID or GUID that can be paired with the ViewModel:

public class UserViewModel
{
    public string UserId { get; set; }
    public string ConnectionId { get; set; }

    public UserViewModel() { }
    public UserViewModel(string UserId, string ConnectionId)
    {
        this.UserId = UserId;
        this.ConnectionId = ConnectionId;
    }
}

      

The connection method will be processed when the user connects. It will first see if the connected user is already in the ConnectedUsers list, and it does this by looking at the user by their ConnectionId and their UserId. If they don't exist, they are added to the list, but if they exist, we move on to the SetConnection method.

In the SetConnection method we get the UserId and we do a search to make sure there is an existing user in the list. If we find an existing user, we remove them from the list, update their connection ID, and put them back in the list. This helps to ensure that Count has the correct number of users. You will notice that there is a Connect call in the SetConnection method, and I will explain this a little later.

Next is the Disconnect method. It will look for the user in the ConnectedUser list with its UserId (which is important because this is the one that always stays the same) and deletes them. This method will be called when the user logs out OR using our OnDisconnect method.

The OnDisconnect method is the one you see I have overridden. This is called when a user navigates to another page on your site or leaves the site entirely (more on this later).



Now we can look at our JS:

$(document).ready(function () {
    var shub = $.connection.securityHub;
    $.connection.hub.start().done(function () {
        Connect(shub);
    });

    //Client calls here
});

//Server calls here

function Connect(shub) {
    var id = $('#unique-user-id').attr('data-uid');

    if (Cookies.get('Connected') == null) {
        Cookies.set('Connected', 'UserConnected', { path: '' });
        shub.server.connect(id);;
    }
    else {
        shub.server.setConnection(id);
    }
}

function Disconnect() {
    Cookies.remove('Connected', { path: '' });
    $.connection.securityHub.server.disconnect();
}

      

Make sure the script tag is added to the master page or _Layout.cshtml with a link to this, because this will need to be run on every page of your site. In part, $(document).ready

it starts the hub every time the page is loaded, which also calls our outside connection method $(document).ready

.

The Connect method takes a hub as an argument and it will find the unique ID that I have set on the page ( $('#unique-user-id')

is an element in my _Layout, so every page will have one, but you can pass UserId any as you want). Then it will look for the cookie which I call Connected. This cookie expires when the session expires, so if they close the tab or browser then the Connected cookie will be deleted. If the cookie is null, I set the cookie and run the Connect method found in Hub.cs. If the cookie already exists, we instead run the SetConnection method so that the existing user can get the new ConnectionId.

I've included a Disconnect method that you can run whenever you want. Once your logout button has been pressed, you can run the disconnect method and it will delete the cookie and disconnect you from the server.

Now I want to talk about the Connect and OnDisconnect methods. This is a method that is triggered EVERY time a user navigates to another page on your site, closes their browser, or leaves a tab from your site. This means that every time a user navigates to a different page on your site, they will be disabled at first (but their associated cookie will remain a tactic because if they navigate to another page, none of our JS methods were called. therefore we have not removed their cookies). As soon as the page loads our JS, it gets fired up and then fired up and started$(document).ready

... It will start the hub, then it will launch the JS Connect method, which will see that the Connect cookie exists, and will run the SetConnection method on the server, which will then find the currently connected user and provide them with a new ConnectionId in our list.

The only interesting part of this is that if you show a list of connected users, they will flicker when they navigate to other pages. I mean it means you are just showing the user counter ( ConnectedUsers.Count

) in a div or something. Let's say you have 5 connected users, one of those users will navigate to another page, the count will briefly jump to 4 (since the OnDisconnect method will run) and then back to 5 (because JS calls the Connect method).

One thing you can do differently is instead of passing the UserId through JS like I did in the Hub.cs class, you can just get the UserId like this Context.User.Identity.GetUserId()

, which would probably be better than it would be like data attribute on the page. If you want to do this, make sure you include it using: using Microsoft.AspNet.Identity

. This was exactly how I decided to do it.

+2


source







All Articles