在SignalR中,有时断开连接事件无法触发

4
我目前将用户保留在名为OnlineUsers的表中。当一个人连接或断开连接时,它会将用户ID和连接ID添加到表中,但出现问题(我认为当多个浏览器窗口打开时),Disconnect函数有时不会触发,导致将用户保留在表中并使其看起来是“在线”的,而实际上他们并不在线。有没有人遇到过这个问题,并想知道如何解决这个问题?
更新 **(抱歉没有放置代码,我应该一开始就做到这一点)
以下是我的数据库函数,用于向表中添加和删除:
    public bool ConnectUser(Guid UserId, String ConnectionId)
            {
                if (!Ent.OnlineUsers.Any(x => x.UserId == UserId && x.ConnectionId == ConnectionId))
                {
                    Ent.OnlineUsers.AddObject(new OnlineUser { UserId = UserId, ConnectionId = ConnectionId });
                    Ent.SaveChanges();
                    return true;
                }
                else
                    return false;
            }
            public void DisconnectUser(Guid UserId, String ConnectionId)
            {
                if (Ent.OnlineUsers.Any(x => x.UserId == UserId && x.ConnectionId == ConnectionId))
                {
                    Ent.OnlineUsers.DeleteObject(Ent.OnlineUsers.First(x => x.UserId == UserId && x.ConnectionId == ConnectionId));
                    Ent.SaveChanges();
                }
            }

这是我的中枢类连接和断开任务:

 public Task Disconnect()
        {

            disconnectUser();                
            return null;
        }
        public Task Reconnect(IEnumerable<string> connections)
        {
            connectUser();                
            return null;
        }
        public Task Connect()
        {
            connectUser();               
            return null;
        }
private void connectUser()
        {
            if (onlineUserRepository.ConnectUser(MainProfile.UserId, Context.ConnectionId))
            {
                Groups.Add(Context.ConnectionId, Convert.ToString(MainProfile.ChatId));
            }
        }
        private void disconnectUser()
        {
            onlineUserRepository.DisconnectUser(MainProfile.UserId, Context.ConnectionId);
            Groups.Remove(Context.ConnectionId, Convert.ToString(MainProfile.ChatId));
        }

我已经检查过,我在使用最新版本的SignalR(0.5.3),当我同时关闭多个浏览器窗口时,会出现这种情况,用户将被卡在数据库中。如果需要的话,以下是我的连接ID生成器类:
public class MyConnectionFactory : IConnectionIdGenerator
    {
        public string GenerateConnectionId(IRequest request)
        {            
            if (request.Cookies["srconnectionid"] != null)
            {
                return request.Cookies["srconnectionid"].ToString();
            }

            return Guid.NewGuid().ToString();
        }
    }

2
你在使用哪个版本的SignalR?我以前遇到过0.5.3之前的版本时有间歇性问题;自从那时起,我的连接/断开连接一直非常稳定。此外,发布源代码是诊断SignalR问题(或者实际上是您在SO上发布的任何问题)的一种要求。最后,您能否测试不同的浏览器以查看它们的行为是否不同? - Heather
我检查了一下,现在我正在使用 signalR 版本 0.5.3,但出现问题的原因仍然存在。我可以缩小问题范围,发现当多个浏览器窗口同时打开并且我一次性关闭它们时,问题就会出现。 - anthonypliu
@Heather 我也添加了我的连接 ID 创建器,也许这可能是问题的原因。 - anthonypliu
1个回答

7
我认为您的连接工厂确实存在问题。如果没有找到cookie,则会生成一个新的guid,但此时为时已晚。
我的理解是连接ID由客户端(客户端侧的Hub)在初始化期间建立,并且不能在服务器上更改;它只能被读取。实际上,在找不到cookie时返回新的Guid时,您正在更改客户端ID。
在我的连接工厂中,如果找不到cookie,我会抛出异常。在打开使用Signalr的页面的控制器操作中,我确保种植了cookie。
这是我的连接工厂:
public class ConnectionFactory : IConnectionIdGenerator
{
    public string GenerateConnectionId(IRequest request)
    {
        if (request.Cookies["UserGuid"] != null)
            return request.Cookies["UserGuid"].Value;

        throw new ApplicationException("No User Id cookie was found on this browser; you must have cookies enabled to enter.");
    }
}

如果页面上打开了多个浏览器窗口来创建连接ID,该怎么办?在我的情况下,如何处理多个浏览器窗口。再次感谢您的帮助! - anthonypliu
多个浏览器实例将都可以访问相同的cookie,因此它们将通过相同的ID连接,除非您每次发出cookie时更改其值。无论如何,该cookie的值最终将成为ID,而不管打开了多少个浏览器窗口,如果某些窗口具有相同的ID,而其他窗口具有不同的ID,则也没有关系。 - Heather

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接