SignalR如何向除请求发起者外的所有用户发送消息
问题分析与解决方案
错误原因
你当前的代码存在两个核心问题:
- AllExcept参数用错:
AllExcept方法需要传入要排除的SignalR连接ID数组,而不是用户名/组名,你传入用户名自然不会生效。 - GroupExcept参数用错:
GroupExcept的第一个参数是目标组名,第二个参数是要排除的连接ID列表,你两次传入组名等于没有排除任何连接,所以所有组内用户都能收到消息。
解决方案
结合你已经将每个用户的所有连接加入对应用户名组的设计,提供两种适配你需求的实现方式:
方法1:给所有用户发消息,排除当前请求用户(推荐)
因为你已经把用户的所有连接都归类到以用户名命名的组中,直接用AllGroupsExcept方法排除当前用户的组即可,无需维护额外的连接映射:
string currentUserName = this.User.Identity.Name ?? "Service"; // 向所有组发送消息,排除当前用户的组(即当前用户的所有连接都收不到) await _hubContext.Clients.AllGroupsExcept(currentUserName).SendAsync("AtualizaPosicaoCardOP", "Mensagem aqui");
方法2:精确排除当前用户的单个/多个连接
如果需要针对当前用户的特定连接进行排除,需要先在Hub中维护用户名与连接ID的映射关系:
// 在MesHub类中添加并发安全的连接映射 private static readonly ConcurrentDictionary<string, List<string>> UserConnections = new ConcurrentDictionary<string, List<string>>(); public override Task OnConnectedAsync() { string name = Context.User.Identity.Name ?? "Service"; // 将当前连接ID添加到对应用户的连接列表 UserConnections.AddOrUpdate( name, new List<string> { Context.ConnectionId }, (key, existingList) => { existingList.Add(Context.ConnectionId); return existingList; }); await Groups.AddToGroupAsync(Context.ConnectionId, name); return base.OnConnectedAsync(); } public override Task OnDisconnectedAsync(Exception exception) { string name = Context.User.Identity.Name ?? "Service"; // 断开连接时移除对应映射 if (UserConnections.TryGetValue(name, out var connections)) { connections.Remove(Context.ConnectionId); if (connections.Count == 0) { UserConnections.TryRemove(name, out _); } } return base.OnDisconnectedAsync(exception); }
然后在控制器中通过用户名获取连接ID列表,再用AllExcept排除:
string currentUserName = this.User.Identity.Name ?? "Service"; if (MesHub.UserConnections.TryGetValue(currentUserName, out var connectionIds)) { // 排除当前用户的所有连接,给其他用户发消息 await _hubContext.Clients.AllExcept(connectionIds.ToArray()).SendAsync("AtualizaPosicaoCardOP", "Mensagem aqui"); } else { // 当前用户无在线连接,直接发送给所有用户 await _hubContext.Clients.All.SendAsync("AtualizaPosicaoCardOP", "Mensagem aqui"); }
GroupExcept的正确用法
如果你的需求是给某个特定组发消息,同时排除组内的部分连接,正确写法如下:
// 示例:给名为"TargetGroupName"的组发消息,排除连接ID为"connId1"、"connId2"的客户端 await _hubContext.Clients.GroupExcept("TargetGroupName", new[] { "connId1", "connId2" }).SendAsync("AtualizaPosicaoCardOP", "Mensagem aqui");
内容的提问来源于stack exchange,提问作者Renan
相关产品推荐
相关产品推荐

