使用SignalR时如何检查指定标识的用户是否存在?
问题:SignalR发送消息前验证目标用户是否存在
在Hub文件的静态函数中通过SignalR向客户端发送消息,现有代码运行正常,但传入随机无效UserID时不会报错。希望添加判断逻辑:若指定UserID的用户存在(在线)则发送消息,不存在则抛出异常,请问如何实现?
现有代码示例:
public static void CallTestFunction(int UserID, short TestParam) { try { var hubContext = GlobalHost.ConnectionManager.GetHubContext<TestHub>(); hubContext.Clients.User(UserID.ToString()).TestFunction(TestParam); } catch (Exception ex) { Logger.LogError(ex); } }
期望实现的逻辑:
public static void CallTestFunction(int UserID, short TestParam) { try { var hubContext = GlobalHost.ConnectionManager.GetHubContext<TestHub>(); if(// 检查用户是否存在的逻辑) hubContext.Clients.User(UserID.ToString()).TestFunction(TestParam); else // 抛出用户不存在的异常 } catch (Exception ex) { Logger.LogError(ex); } }
实现方案
SignalR本身没有提供直接查询指定用户是否在线的API,所以需要自行维护在线用户的状态集合,结合Hub的连接生命周期事件更新集合,之后在发送消息前检查集合中是否存在目标用户。
步骤1:维护在线用户集合
在TestHub中定义线程安全的静态集合,用于存储当前在线用户的ID(多用户同时连接/断开时需保证线程安全):
public class TestHub : Hub { // 线程安全字典:Key为UserID字符串,Value为该用户的在线连接ID集合(支持多端登录) private static readonly ConcurrentDictionary<string, HashSet<string>> OnlineUsers = new ConcurrentDictionary<string, HashSet<string>>(); // 用户连接成功时触发 public override Task OnConnected() { // 从身份上下文获取当前用户ID(根据你的实际验证逻辑调整,比如自定义Claim) string userId = Context.User.Identity.Name; if (!string.IsNullOrEmpty(userId)) { // 将当前连接ID添加到用户的连接集合中 OnlineUsers.AddOrUpdate(userId, key => new HashSet<string> { Context.ConnectionId }, (key, existingConnections) => { existingConnections.Add(Context.ConnectionId); return existingConnections; }); } return base.OnConnected(); } // 用户断开连接时触发 public override Task OnDisconnected(bool stopCalled) { string userId = Context.User.Identity.Name; if (!string.IsNullOrEmpty(userId) && OnlineUsers.TryGetValue(userId, out var connections)) { connections.Remove(Context.ConnectionId); // 若用户无在线连接,则从字典中移除 if (connections.Count == 0) { OnlineUsers.TryRemove(userId, out _); } } return base.OnDisconnected(stopCalled); } // 对外提供静态方法,查询用户是否在线 public static bool IsUserOnline(string userId) { return OnlineUsers.ContainsKey(userId); } }
步骤2:修改静态函数添加验证逻辑
在CallTestFunction中调用TestHub.IsUserOnline检查用户状态,不存在则抛出异常:
public static void CallTestFunction(int UserID, short TestParam) { try { string userIdStr = UserID.ToString(); var hubContext = GlobalHost.ConnectionManager.GetHubContext<TestHub>(); // 验证用户是否在线 if (TestHub.IsUserOnline(userIdStr)) { hubContext.Clients.User(userIdStr).TestFunction(TestParam); } else { // 抛出异常(可自定义业务异常,更清晰区分错误类型) throw new ArgumentException($"用户ID {UserID} 不存在或未在线", nameof(UserID)); } } catch (Exception ex) { Logger.LogError(ex); } }
注意事项
- 身份验证适配:
Context.User.Identity.Name需根据你的实际身份验证方式调整,比如使用自定义Claim存储UserID时,改用Context.User.FindFirst("UserID")?.Value。 - 线程安全:必须使用
ConcurrentDictionary保证多线程环境下的集合操作安全,避免竞态问题。 - 异常设计:可自定义
UserNotFoundException替代ArgumentException,让错误语义更明确。
内容的提问来源于stack exchange,提问作者Pawan Alur
相关产品推荐
相关产品推荐

