You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 06:36:18