C# 使用信号集线器向特定连接用户广播消息
我的目标是在数据库发生插入/更新时立即通知连接的用户 我有一个C# 使用信号集线器向特定连接用户广播消息,c#,javascript,asp.net-mvc,signalr,C#,Javascript,Asp.net Mvc,Signalr,我的目标是在数据库发生插入/更新时立即通知连接的用户 我有一个集线器 [Authorize] public class NotificationsHub : Hub { private readonly IWorker _worker; public NotificationsHub() : this(new WorkerFacade(new ExtremeDataRepository())) { } public NotificationsHub(IWorker w
集线器
[Authorize]
public class NotificationsHub : Hub
{
private readonly IWorker _worker;
public NotificationsHub() : this(new WorkerFacade(new ExtremeDataRepository())) { }
public NotificationsHub(IWorker worker)
{
_worker = worker;
}
public override Task OnConnected()
{
if (!HubUsersManager.ConnectedUsers.Any(p => p.Name.Equals(Context.User.Identity.Name)))
{
HubUsersManager.ConnectedUsers.Add(new HubUserHandler
{
Name = Context.User.Identity.Name,
ConnectionId = Context.ConnectionId
});
}
return base.OnConnected();
}
//public override Task OnDisconnected()
//{
// HubUserHandler hubUserHandler =
// HubUsersManager.ConnectedUsers.FirstOrDefault(p => p.Name == Context.User.Identity.Name);
// if (hubUserHandler != null)
// HubUsersManager.ConnectedUsers.Remove(hubUserHandler);
// return base.OnDisconnected();
//}
public async Task<ICollection<NotificationMessage>> GetAllPendingNotifications(string userId)
{
return await _worker.GetAllPendingNotifications(userId);
}
public void UpdateNotificationMessagesToAllClients(ICollection<NotificationMessage> notificationMessages)
{
Clients.All.updateNotificationMessages(notificationMessages);
}
}
我知道映射可能不是必需的,我可以重写实现,将其映射到我的实际ApplicationUser
GUID Id以避免它,但现在它似乎可以达到这个目的,如果我首先让它工作,它可能会改变它
您还可以看到IWorker
引用,如果客户端调用服务器方法,我将使用该引用获取一些数据。
此外,IWorker
具体实现正在被所有控制器使用,并且具有属性客户端
,因此我可以立即将消息广播回连接的客户端
private IHubConnectionContext _clients;
private IHubConnectionContext Clients
{
get {
return _clients ?? (_clients = GlobalHost.ConnectionManager.GetHubContext<NotificationsHub>().Clients);
}
}
我的浏览器中没有任何内容,应该会弹出两个警报,一个在更新通知中说Im
,另一个是testmessage
,就像您在上面的Javascript
代码中看到的那样
[编辑]
更改代码以将消息发送到特定的组
,但在我的客户端浏览器中不会再次显示任何内容
public override Task OnConnected()
{
if (_groupManager.Count == 0)
{
ICollection<string> rolesCollection = _worker.GetAllRoles();
foreach (string roleName in rolesCollection)
{
_groupManager.Add(roleName);
}
}
foreach (string groupRole in _groupManager.Groups)
{
if (Context.User.IsInRole(groupRole))
{
Groups.Add(Context.ConnectionId, groupRole);
}
}
return base.OnConnected();
}
public override任务OnConnected()
{
如果(_groupManager.Count==0)
{
ICollection rolesCollection=_worker.GetAllRoles();
foreach(角色集合中的字符串roleName)
{
_groupManager.Add(roleName);
}
}
foreach(字符串groupRole在_groupManager.Groups中)
{
if(Context.User.IsInRole(groupRole))
{
添加(Context.ConnectionId,groupRole);
}
}
返回base.OnConnected();
}
在我工人阶级的某个地方:
List<NotificationMessage> testList = new List<NotificationMessage>
{
new NotificationMessage {Message = "TEST MESSAGE!"}
};
Clients.Group("TestGroup").updateNotificationMessages(testList);
List testList=新列表
{
新建通知消息{Message=“TEST Message!”}
};
Clients.Group(“TestGroup”).updateNotificationMessages(testList);
我想我错过了什么 我的2美分:你看过Clients.User()方法了吗?它已经为您完成了所有的ConnectionId
映射,并且您正在使用Context.User
,因此它应该是现成的。如果需要更复杂的东西,可以在IUserIdProvider
的自定义实现中编写自己的映射逻辑。至少你会消除一个层次的复杂性(但如果不是因为这个问题,你不确定它会解决你的具体问题)。只是一个想法。是的,我将把逻辑移到IUserIdProvider,因为我使用ASP.NET身份验证,所以它看起来更好。我将尝试Clients.User()empty重载。Clients.User()对我的问题没有意义,因为我可能连接了多个用户,他们需要接收相同的消息。我不认为这与使用ConnectionId的方法有什么不同。与通过“不安全”的连接ID进行循环不同,您将通过用户ID进行循环,这是一个不太需要解决的问题。此外,我建议您看看是否可以找到一种方法,以某种方式对用户进行分组(例如使用角色),并利用SignalR提供的组支持,这样您就可以通过一次呼叫同时访问所有用户。也许你可以在这个方向上回顾你的逻辑。是的,我同意你的评论,我将删除当前的逻辑,并尝试从中心使用Groups和ConnectionId构建新的逻辑。有没有办法让所有当前连接到集线器客户端的ConnectionID?我知道IUserIdProvider将允许我将ConnectionId映射到数据库中的User.Identity id。当然,对于群组,我只需要说发送消息给群组,所有连接到群组的客户端理论上都会收到通知!虽然没有办法获得所有当前的连接ID,但即使这样,也有可能不是推荐的方法。处理ConnectionId越少越好,而且通常可以在不使用它们的情况下重新构造代码来解决问题。团队在这方面真的很棒。
public override Task OnConnected()
{
if (_groupManager.Count == 0)
{
ICollection<string> rolesCollection = _worker.GetAllRoles();
foreach (string roleName in rolesCollection)
{
_groupManager.Add(roleName);
}
}
foreach (string groupRole in _groupManager.Groups)
{
if (Context.User.IsInRole(groupRole))
{
Groups.Add(Context.ConnectionId, groupRole);
}
}
return base.OnConnected();
}
List<NotificationMessage> testList = new List<NotificationMessage>
{
new NotificationMessage {Message = "TEST MESSAGE!"}
};
Clients.Group("TestGroup").updateNotificationMessages(testList);