关于将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表将随着时间放大而没有任何用处。
答案 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();
}
这是否符合您的想法?