2013-07-11 30 views
1

我的应用有一堆UserGroups。SignalR在浏览器刷新时加入群组新的Context.ConnectionId

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

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

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

因此,我喜欢Jabbr Chatrooms,但我不想设置它,因为应用程序有不同的意图。因此,当客户端登录时,他们将根据下拉列表中选定项目的值加入组。我注意到,无论什么时候我刷新页面作为客户端,'Join'服务器方法再次被调用一个新的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,这工作得很好。正如你所看到的,它传递了一个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); 
} 

我最关心的又是作为方法addMessage部分工作join方法!管理员发送通知,客户端看到它们。问题是如果客户端刷新他们的浏览器在服务器上再次调用Join(我得到了一个设置的断点)并且它有一个新的Context.ConnectionId。这不好吗?这是否会造成更多的连接?是否有JavaScript/jQuery调用,我应该确保在客户端的窗口关闭的情况下销毁该连接,如果浏览器刷新问题又如何呢?

感谢您的任何想法。

回答

0

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

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

+0

小心详细说明如何做(防止刷新之间的连接,循环)?谢谢 –

+0

我并不真正了解应用程序的确切上下文,但一种方法是转到一个现代的单页应用程序(SPA)模型,在SPA启动时连接SignalR连接,然后可以动态加载在你的应用程序的各个部分,因为你需要它们。 –

0

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

你可以抓住上使用下面的代码的OnConnected()方法会话:

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

,并将其存储与的ConnectionId在DB一起。在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中,请确保您的会话自动regenrated:

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

希望这会有所帮助。