1

我的应用程序有一堆用户组。

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

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

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

因此,我猜我的做法就像 Jabbr Chatrooms,但我不想设置太多,因为该应用程序有不同的意图。因此,当客户端登录时,他们会根据下拉列表中 Selected 项的值加入一个组。我确实注意到,每当我以客户端身份刷新页面时,都会使用新的 connectionId 再次调用“加入”服务器方法。这是正确的吗?我不想拥有比实际更多的联系。当他们更改下拉列表时,我还需要断开客户端与组的连接并将他们重新加入新组。

我正在寻找演示,但找到非常简单的演示或非常复杂的演示,我最初的目标是介于两者之间,因为我打算在网站的其他区域添加 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);
        }
}

管理页面调用 SendNotificationsToGroups 并且这工作正常。如您所见,它传递了一个整数数组,这些整数是要向其广播通知的组。我只是 .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);
}

我主要关心的是 addMessage 部分工作时的 join 方法!管理员发送通知,客户看到它们。问题是如果客户端刷新他们的浏览器 Join 在服务器上再次被调用(我在它上面设置了一个断点)并且它有一个新的 Context.ConnectionId。这很糟糕吗?这是否会导致不必要的连接。如果关闭客户端的窗口离开页面,我应该进行 javascript/jQuery 调用以确保连接被破坏,那么浏览器刷新问题呢?

感谢您的任何想法。

4

2 回答 2

0

SignalR挂钩窗口的卸载事件并调用.stop()连接,但它使用异步消息执行此操作,因此它可能不会立即发生。此外,服务器端将自动检测并清除“死”连接,作为其家务琐事的一部分。

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

于 2013-07-12T00:21:58.413 回答
0

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

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

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

并将其与 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 中,确保您的会话自动重新生成:

<sessionState mode="InProc" cookieless="false" regenerateExpiredSessionId="true"></sessionState>

希望这可以帮助。

于 2013-08-16T23:32:54.797 回答