SignalR Join组在浏览器刷新时新建Context.ConnectionId

时间:2013-07-11 15:30:39

标签: signalr

我的应用有很多UserGroups。

有一个管理员页面可以向一个或多个这些用户组发送通知。

我有一个Hub,管理员可以通过对WebAPI方法的AJAX调用将通知发布到数据库之后发布。当这在Ajax成功部分返回时,我然后在服务器中心上调用一个方法,该方法将通知实时发布到一个或多个组。这些组由int数组指示,它通过仅使用.ToString()转换int来创建组名。

客户端在其主页上有一个显示通知的小部件。某些用户可以是多个用户组的一部分,但是他们在页面顶部有一个下拉列表,用于指定他们当前正在查看的UserGroupd。因此,它们可能是许多用户组的一部分,但一次只能查看1个。

因此我觉得我喜欢Jabbr Chatrooms,但我不想这么做,因为应用程序有不同的意图。因此,当客户端登录时,他们会根据下拉列表中Selected项的值加入组。我注意到每当我作为客户刷新页面时,就会加入'使用新的connectionId再次调用server方法。这是正确的吗?我不想拥有比实际更多的连接。我还需要断开客户端与组的连接,并在更改下拉列表时将其重新加入新组。

我正在寻找演示,但找到非常简单的演示或非常复杂的演示,我最初的目标是介于两者之间,因为网站的其他区域我打算添加SignalR功能,所以不要过度锁定我的对象模型。

所以在我的中心我得到了:

public void Join(string groupName) {
  Groups.Add(Context.ConnectionId, groupName);
}

public void SendNotificationsToGroups(string title, string description, int[] groups) {
        foreach (int i in groups) {
            Clients.OthersInGroup(i.ToString()).addMessage(Title, description);
        }
}

Admin页面调用SendNotificationsToGroups,这很好用。如您所见,它会传递一组int,这些组是广播通知的组。我只是.ToString int来创建GroupNames。

客户执行以下操作:

var Hub = $.connection.myHub;

Hub.client.addMessage = function (title, description) {
  $('#Notification').find('tr:first').before('<tr><td>'+title+description'</td></tr>');
}

$.connection.hub.start().done(function () {
    var groupId = $('#userGroupID').val();
    newsHub.server.join(groupId);
}

我主要关心的是add方法,因为addMessage部分可以正常工作!管理员发送通知,客户端看到它们。问题是如果客户端刷新他们的浏览器在服务器上再次调用Join(我在其上设置了断点)并且它有一个新的Context.ConnectionId。这不好吗?这是否导致了更多的连接。是否存在javascript / jQuery调用,我应该确保连接如果窗口关闭,客户端离开页面就会被破坏,浏览器刷新问题又如何呢。

感谢任何想法。

2 个答案:

答案 0 :(得分:0)

SignalR hooks the window's unload event and calls .stop() on the connection,但它使用异步消息进行,因此可能不会立即发生。此外,服务器端将自动检测并清除“死”连接,作为其家务杂务的一部分。

也就是说,如果您可以在每个页面导航上断开/重新连接,最好保持SignalR连接处于活动状态。不断断开和重新连接有点失败的目的,你显然可能会错过页面导航之间的一些消息。

答案 1 :(得分:0)

我解决它的方法是将用户的会话和connectionId存储在与用户一对多的表中。例如,您可以创建一个PersonSession表来存储上述内容以及其他信息,例如主机,连接时间,断开连接时间和用户代理。

您可以使用以下代码在OnConnected()方法上获取会话:

var session = Context.RequestCookies.ContainsKey("ASP.NET_SessionId") ? Context.RequestCookies["ASP.NET_SessionId"].Value : null;

并将其与db中的connectionId一起存储。在OnDisconnected()方法中,您只需使用DisconnectTiemstamp更新此记录。

然后当他们刷新时,你可以检查以前的记录(我随时为用户保留最多3条记录),看看他们是否有相同的会话,如果有,那么你就不会更新,否则,您假设这是一个新会话并进行更新。

if (session != null)
{
     var MyInActiveSessions = p.PersonSessions.Where(x=>x.DisconnectTimestamp != null);
                            bUpdateStatus = !MyInActiveSessions.Any(x => x.SessionID != null &&          x.SessionID == session);
}

另外,请记住,您必须在登录时强制重新生成会话cookie,因为即使您注销,ASP.net也会保留旧的会话cookie。要做到这一点,你需要做几件事:

  1. 在您的登录代码中,将任意随机值放入Session变量以强制ASP.NET生成cookie(例如Session['0'] = 0;
  2. 在您的退出代码中,放弃会话并将Cookie添加到响应中:

    Session.Abandon(); Response.Cookies.Add(new HttpCookie("ASP.NET_SessionId", ""));

  3. 最后,在Web.config中,确保您的会话自动重新生成:
  4. <sessionState mode="InProc" cookieless="false" regenerateExpiredSessionId="true"></sessionState>

    希望这有帮助。