使用SQL Server

时间:2015-09-28 15:53:18

标签: asp.net sql-server asp.net-mvc signalr signalr-hub

关于将SignalR用户映射到连接,我读了这个topic。简而言之,该主题解释了四种映射方法,我想使用第四种方法(永久性,外部存储)。该方法使用SQL Server数据库在客户端连接时(ConnectionId方法被触发时)和客户端关闭浏览器时(OnConnected方法被触发时)存储OnDisconnected它只是让ConnectionId无效。

以下是数据库的代码:

public class UserContext : DbContext
{
    public DbSet<User> Users { get; set; }
    public DbSet<Connection> Connections { get; set; }
}

public class User
{
    [Key]
    public string UserName { get; set; }
    public ICollection<Connection> Connections { get; set; }
}

public class Connection
{
    public string ConnectionID { get; set; }
    public string UserAgent { get; set; }
    public bool Connected { get; set; }
}

以下是集线器类中的代码:

[Authorize]
public class ChatHub : Hub
{
    public void SendChatMessage(string who, string message)
    {
        var name = Context.User.Identity.Name;
        using (var db = new UserContext())
        {
            var user = db.Users.Find(who);
            if (user == null)
            {
                Clients.Caller.showErrorMessage("Could not find that user.");
            }
            else
            {
                db.Entry(user)
                    .Collection(u => u.Connections)
                    .Query()
                    .Where(c => c.Connected == true)
                    .Load();

                if (user.Connections == null)
                {
                    Clients.Caller.showErrorMessage("The user is no longer connected.");
                }
                else
                {
                    foreach (var connection in user.Connections)
                    {
                        Clients.Client(connection.ConnectionID)
                            .addChatMessage(name + ": " + message);
                    }
                }
            }
        }
    }

    public override Task OnConnected()
    {
        var name = Context.User.Identity.Name;
        using (var db = new UserContext())
        {
            var user = db.Users
                .Include(u => u.Connections)
                .SingleOrDefault(u => u.UserName == name);

            if (user == null)
            {
                user = new User
                {
                    UserName = name,
                    Connections = new List<Connection>()
                };
                db.Users.Add(user);
            }

            user.Connections.Add(new Connection
            {
                ConnectionID = Context.ConnectionId,
                UserAgent = Context.Request.Headers["User-Agent"],
                Connected = true
            });
            db.SaveChanges();
        }
        return base.OnConnected();
    }

    public override Task OnDisconnected(bool stopCalled)
    {
        using (var db = new UserContext())
        {
            var connection = db.Connections.Find(Context.ConnectionId);
            connection.Connected = false;
            db.SaveChanges();
        }
        return base.OnDisconnected(stopCalled);
    }
}

我想增强此方法,因为使用此方法将创建许多根本不需要的ConnectionIds。此外,使用此方法,Connections表将随着时间放大而没有任何用处。

1 个答案:

答案 0 :(得分:2)

如何清理connectionIds而不是将Connected属性设置为false?您的OnDisconnnected()方法可能如下所示:

public override Task OnDisconnected(bool stopCalled)
{
    using (var db = new UserContext())
    {
        var connection = db.Connections.Find(Context.ConnectionId);
        db.Connections.Remove(connection);
        db.SaveChanges();
    }
    return base.OnDisconnected(stopCalled);
}

这会阻止Connections表无限增长。然后,您可以完全删除Connected属性,并且连接行的存在表明连接处于活动状态。

更新

另一种方法,如果您不想删除记录但重新使用数据库中已有的记录,可能如下所示:

public override Task OnConnected()
{
    var name = Context.User.Identity.Name;
    using (var db = new UserContext())
    {
        var user = db.Users
            .Include(u => u.Connections)
            .SingleOrDefault(u => u.UserName == name);

        if (user == null)
        {
            user = new User
            {
                UserName = name,
                Connections = new List<Connection>()
            };
            db.Users.Add(user);
        }

        var connection = user.Connections.Where(c => c.Connected == false && UserAgent == Context.Request.Headers["User-Agent"]).FirstOrDefault();
        if (connection == null) 
        {
             connection = new Connection();
             connection.UserAgent = Context.Request.Headers["User-Agent"];
             user.Connections.Add(connection);
        }

        connection.ConnectionID = Context.ConnectionId;
        connection.Connected = true;
        db.SaveChanges();
    }
    return base.OnConnected();
}

这是否符合您的想法?