Signalr 从多个页面连接信号器集线器

Signalr 从多个页面连接信号器集线器,signalr,Signalr,在我的应用程序中,我需要从一个页面连接到SignalrHub,然后我想重定向到另一个页面,并且仍然使用相同的signalR连接与服务器进行交互。 如果我从一个页面Page1连接到信号集线器,并重定向到另一个页面,则Page1中的聊天对象无效 ***var chat = $.connection.chatHub; // Start the connection. $.connection.hub.start().done(function () {});*** 我还尝试将聊天变量保存到创建到si

在我的应用程序中,我需要从一个页面连接到SignalrHub,然后我想重定向到另一个页面,并且仍然使用相同的signalR连接与服务器进行交互。 如果我从一个页面Page1连接到信号集线器,并重定向到另一个页面,则Page1中的聊天对象无效

***var chat = $.connection.chatHub;
// Start the connection.
$.connection.hub.start().done(function () {});***
我还尝试将聊天变量保存到创建到signalR hub连接的页面中的sessionStorage,然后在另一个页面中还原它,但没有成功


是否有一种方法可以从第1页连接到信号集线器,并从另一页使用相同的连接(使用相同的连接ID)?

因此,如果我正确理解您的问题,那么您希望在导航到另一页时,能够将同一用户连接到您的信号集线器。如果是这样的话,我就想出了一个对我来说非常有效的解决方案

以下是hub类中的方法:

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);
}
连接方法将在用户连接时处理。首先,它将查看一个已连接的用户是否已经包含在ConnectedUsers列表中,并通过其ConnectionId和UserId查找用户来实现这一点。如果它们不存在,则将它们添加到列表中,但如果它们确实存在,则转到SetConnection方法

在SetConnection方法中,我们获得一个UserId,并进行查找以确保列表中存在一个现有用户。如果我们找到一个现有用户,那么我们会将其从列表中删除,更新其连接id,然后将其放回列表中。这有助于确保计数具有正确的用户数。您会注意到,在SetConnection方法中有一个连接调用,稍后我将对此进行解释

接下来是断开连接方法。它将根据用户ID在ConnectedUser列表中查找用户(这一点很重要,因为用户ID始终保持不变),并将其删除。当用户注销时,或通过OnDisconnect方法调用此方法

OnDisconnect方法是您可以看到我已重写的方法。每当用户导航到您站点上的另一个页面或完全离开站点时(稍后将对此进行详细介绍),就会调用此函数

现在我们可以检查我们的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();
}
确保在母版页或_Layout.cshtml中添加一个脚本标记,并对其进行引用,因为这需要在站点的每个页面上运行。在
$(document.ready
部分中,它将在每次加载页面时启动集线器,这也将在
$(document.ready)之外调用我们的连接方法

Connect方法将hub作为参数,它将查找我在页面上设置的唯一ID(
$(“#unique user ID”)
是我的_布局中的一个元素,因此每个页面都会有它,但您可以按任何方式传递用户ID)。然后它会寻找一个我称之为连接的cookie。此cookie在会话过期时过期,因此如果他们关闭选项卡或浏览器,则连接的cookie将消失。如果cookie为null,那么我设置cookie并运行Hub.cs中的Connect方法。如果cookie已经存在,那么我们将运行SetConnection方法,以便现有用户可以获得新的ConnectionId

我已经包括了一个断开连接的方法,可以随时激发。单击注销按钮后,您可以运行disconnect方法,它将删除cookie并断开您与服务器的连接

现在我想谈谈Connect和OnDisconnect方法。此方法在用户每次导航到站点上的另一页、关闭浏览器或退出站点的选项卡时运行。这意味着每次用户首先导航到站点上的另一个页面时,他们都会断开连接(但他们连接的cookie将保持不变,因为如果他们转到另一个页面,我们没有调用任何JS方法,因此我们没有删除他们的cookie)。页面加载后,我们的JS开始发挥作用,
$(document).ready运行,然后运行。它将启动集线器,然后运行JS Connect方法,该方法将看到Connect cookie存在,并在服务器上运行SetConnection方法,该方法将找到当前连接的用户,并在列表中为他们提供一个新的ConnectionId

这其中唯一令人不安的部分是,如果你显示一个已连接用户的列表,当他们转到其他页面时,他们会闪烁。我的意思是,假设您只在div或其他文件中显示用户计数(
ConnectedUsers.count
)。假设您有5个已连接的用户,其中一个用户导航到另一个页面。计数将短暂变为4(因为OnDisconnect方法将运行),然后返回到5(因为JS调用Connect方法)


您可以做一件不同的事情,而不是像我一样通过JS传递用户ID,在Hub.cs类中,您可以像这样获取用户ID:
Context.User.Identity.GetUserId()
,这可能比将其作为页面上的数据属性要好。如果要这样做,请确保使用Microsoft.AspNet.Identity
将其包括在内。这正是我决定这样做的方式。

检查并感谢Nips,我从其他页面连接,得到了相同的连接ID。我想我错了,在从Page1.htm进行初始连接后,我将用户重定向到Page2并重新连接到信号集线器,得到了不同的连接ID。
$(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();
}