客户端调用函数时c#.NET核心信号器异常(并非总是发生)

客户端调用函数时c#.NET核心信号器异常(并非总是发生),c#,signalr,signalr-hub,asp.net-core-signalr,C#,Signalr,Signalr Hub,Asp.net Core Signalr,我有以下服务器信号器集线器: public class AlertHub : Hub { static ConcurrentDictionary<string, string> _users = new ConcurrentDictionary<string, string>(); public Task SendMessage(string user, string message) {

我有以下服务器
信号器
集线器:

 public class AlertHub : Hub
    {
        static ConcurrentDictionary<string, string> _users = new ConcurrentDictionary<string, string>();

        public Task SendMessage(string user, string message)
        {
            return Clients.All.SendAsync("BroadcastMessage", user, message);
        }

        public Task SendMessageToUser(string userUid, string user, string message, string totalMessages)
        {
            var clientId = _users.FirstOrDefault(x => x.Value == userUid).Key;
            return Clients.Client(clientId).SendAsync("BroadcastMessage", user, message, totalMessages);
        }

        public static void ClearState()
        {
            _users.Clear();
        }

        public override Task OnConnectedAsync()
        {
            _users.TryAdd(Context.ConnectionId, Context.ConnectionId);

            return base.OnConnectedAsync();
        }

        public override Task OnDisconnectedAsync(Exception exception)
        {
            string userUid;
            _users.TryRemove(Context.ConnectionId, out userUid);

            return base.OnDisconnectedAsync(exception);
        }

        public void SetUserUid(string userUid)
        {
            _users[Context.ConnectionId] = userUid;
        }
    }
这是完美的,也不例外

然后,在我的客户机上,当我尝试发送消息时,我会执行以下操作:(这通常有效,异常是间歇性的)

这通常可以正常工作,但有时它会开始崩溃,并在服务器中显示以下错误:

Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher.? [?] - MESSAGE: Failed to invoke hub method 'SendMessageToUser'.
 System.ArgumentNullException: Value cannot be null. (Parameter 'connectionId')
这是指当尝试获取clientId时,它在此处返回null:

 var clientId = _users.FirstOrDefault(x => x.Value == userUid).Key; <-- HERE
return Clients.Client(clientId).SendAsync("BroadcastMessage", user, message, totalMessages);
然后该类注册为Singleton DI:

   services.AddSingleton<AlertHubDictionary>();
services.AddSingleton();
最后对Hub类进行替换:

public class AlertHub : Hub
    {
        private readonly ILogger<AlertHub> _logger;
        private AlertHubDictionary _hubDictionary;
        static ConcurrentDictionary<string, string> _users = new ConcurrentDictionary<string, string>();

        public AlertHub(ILogger<AlertHub> logger, AlertHubDictionary hubDictionary)
        {
            _logger = logger;
            _hubDictionary = hubDictionary;
        }
        public Task SendMessage(string user, string message)
        {
            //Clients.Client("").SendAsync("BroadcastMessage", user, message);
            return Clients.All.SendAsync("BroadcastMessage", user, message);
        }

        public Task SendMessageToUser(string userUid, string user, string message, string totalMessages)
        {
            //var clientId = _users.FirstOrDefault(x => x.Value == userUid).Key;
            var clientId = _hubDictionary.UsersDictionary.FirstOrDefault(x => x.Value == userUid).Key;

            using (var scope = _logger.BeginScope("SCOPED_VALUE"))
            {
                _logger.LogInformation($"Send message to userUid {userUid} - {user} with clientId {clientId}.");

            }


            if (clientId == null)
            {
                // the user is not connected
                return Task.FromResult(0);
            }
            else
            {

                return Clients.Client(clientId).SendAsync("BroadcastMessage", user, message, totalMessages);
            }
        }

        public void ClearState()
        {
            _hubDictionary.ClearUsersDictionary();
            //_users.Clear();

            using (var scope = _logger.BeginScope("SCOPED_VALUE"))
            {
                _logger.LogInformation("_users cleared");

            }

        }

        public override Task OnConnectedAsync()
        {
            _hubDictionary.UsersDictionary.TryAdd(Context.ConnectionId, Context.ConnectionId);
            //_users.TryAdd(Context.ConnectionId, Context.ConnectionId);

            using (var scope = _logger.BeginScope("SCOPED_VALUE"))
            {
                _logger.LogInformation($"ConnectionId {Context.ConnectionId} connected.");

            }

            return base.OnConnectedAsync();
        }

        public override Task OnDisconnectedAsync(Exception exception)
        {
            string userUid;
            _hubDictionary.UsersDictionary.TryRemove(Context.ConnectionId, out userUid);

            using (var scope = _logger.BeginScope("SCOPED_VALUE"))
            {
                _logger.LogInformation($"UserUid {userUid} disconnected.");

            }


            return base.OnDisconnectedAsync(exception);
        }

        public void SetUserUid(string userUid)
        {
            _hubDictionary.UsersDictionary[Context.ConnectionId] = userUid;

            using (var scope = _logger.BeginScope("SCOPED_VALUE"))
            {
                _logger.LogInformation($"Connection {Context.ConnectionId} linked to userUid {userUid}");

            }

            //ClientNameChanged?.Invoke(Context.ConnectionId, userName);
        }
    }
公共类AlertHub:Hub
{
专用只读ILogger\u记录器;
私人AlertHubDictionary\u hubDictionary;
静态ConcurrentDictionary_用户=新ConcurrentDictionary();
公共AlertHub(ILogger记录器、AlertHub字典)
{
_记录器=记录器;
_hubDictionary=hubDictionary;
}
公共任务发送消息(字符串用户,字符串消息)
{
//Clients.Client(“”).sendsync(“广播消息”,用户,消息);
返回Clients.All.sendsync(“BroadcastMessage”,用户,消息);
}
公共任务SendMessageToUser(字符串userUid、字符串用户、字符串消息、字符串totalMessages)
{
//var clientId=\u users.FirstOrDefault(x=>x.Value==userUid.Key;
var clientId=\u hubDictionary.UsersDictionary.FirstOrDefault(x=>x.Value==userUid.Key);
使用(var scope=\u logger.BeginScope(“SCOPED\u值”))
{
_logger.LogInformation($“使用clientId{clientId}向userUid{userUid}-{user}发送消息”);
}
if(clientId==null)
{
//用户未连接
返回Task.FromResult(0);
}
其他的
{
返回Clients.Client(clientId.SendAsync(“BroadcastMessage”、user、message、totalMessages);
}
}
公屋
{
_hubDictionary.ClearUsersDictionary();
//_user.Clear();
使用(var scope=\u logger.BeginScope(“SCOPED\u值”))
{
_logger.LogInformation(“_用户已清除”);
}
}
公共覆盖任务OnConnectedAsync()
{
_hubDictionary.UsersDictionary.TryAdd(Context.ConnectionId,Context.ConnectionId);
//_users.TryAdd(Context.ConnectionId,Context.ConnectionId);
使用(var scope=\u logger.BeginScope(“SCOPED\u值”))
{
_logger.LogInformation($“ConnectionId{Context.ConnectionId}connected.”);
}
返回base.OnConnectedAsync();
}
公共覆盖任务OnDisconnectedAsync(异常)
{
字符串userUid;
_hubDictionary.UsersDictionary.TryRemove(Context.ConnectionId,out userUid);
使用(var scope=\u logger.BeginScope(“SCOPED\u值”))
{
_logger.LogInformation($“UserUid{UserUid}已断开连接。”);
}
返回base.OnDisconnectedAsync(异常);
}
公共void SetUserUid(字符串userUid)
{
_hubDictionary.UsersDictionary[Context.ConnectionId]=userUid;
使用(var scope=\u logger.BeginScope(“SCOPED\u值”))
{
_logger.LogInformation($“连接{Context.ConnectionId}链接到userUid{userUid}”);
}
//ClientNameChanged?.Invoke(Context.ConnectionId,用户名);
}
}

根据您捕获用户ID的方式,您似乎试图将SignalR hub视为一个单独的组件。根据Microsoft文档,hub是一个临时类:

集线器是暂时的:

不要在中心类的属性中存储状态。每个集线器方法 调用在新的中心实例上执行


因此,如果您想保留已注册用户ID的共享实例,您可能应该将其作为一个单独的类进行管理,该类注册为单例并注入到hub类中,以便可以独立于hub维护状态。

将日志记录放入文件中。从添加/清空
\用户
的方法进行日志记录。你可能会时不时地失去连接=这就是为什么它会被清除。太棒了。是的,这完全有道理。任何我可以查看如何实现它的链接?@VAAA-您只需将字典移动到它自己的类中,在启动时注册它就可以了
service.AddSingleton()
,然后使用构造函数注入将其注入到hub的构造函数中,如中所述,这里有一个来自Microsoft的非常类似的独立类示例,尽管标记为internal,但您可以使用public:非常感谢,我将尝试一下刚刚更新了我所做的更改,我将尝试一下。
  public class AlertHubDictionary
    {
        static ConcurrentDictionary<string, string> _users;

        public AlertHubDictionary()
        {
            _users = new ConcurrentDictionary<string, string>();
        }

        public ConcurrentDictionary<string, string> UsersDictionary { get { return _users; } }

        public void ClearUsersDictionary()
        {
            _users.Clear();
        }
    }
   services.AddSingleton<AlertHubDictionary>();
public class AlertHub : Hub
    {
        private readonly ILogger<AlertHub> _logger;
        private AlertHubDictionary _hubDictionary;
        static ConcurrentDictionary<string, string> _users = new ConcurrentDictionary<string, string>();

        public AlertHub(ILogger<AlertHub> logger, AlertHubDictionary hubDictionary)
        {
            _logger = logger;
            _hubDictionary = hubDictionary;
        }
        public Task SendMessage(string user, string message)
        {
            //Clients.Client("").SendAsync("BroadcastMessage", user, message);
            return Clients.All.SendAsync("BroadcastMessage", user, message);
        }

        public Task SendMessageToUser(string userUid, string user, string message, string totalMessages)
        {
            //var clientId = _users.FirstOrDefault(x => x.Value == userUid).Key;
            var clientId = _hubDictionary.UsersDictionary.FirstOrDefault(x => x.Value == userUid).Key;

            using (var scope = _logger.BeginScope("SCOPED_VALUE"))
            {
                _logger.LogInformation($"Send message to userUid {userUid} - {user} with clientId {clientId}.");

            }


            if (clientId == null)
            {
                // the user is not connected
                return Task.FromResult(0);
            }
            else
            {

                return Clients.Client(clientId).SendAsync("BroadcastMessage", user, message, totalMessages);
            }
        }

        public void ClearState()
        {
            _hubDictionary.ClearUsersDictionary();
            //_users.Clear();

            using (var scope = _logger.BeginScope("SCOPED_VALUE"))
            {
                _logger.LogInformation("_users cleared");

            }

        }

        public override Task OnConnectedAsync()
        {
            _hubDictionary.UsersDictionary.TryAdd(Context.ConnectionId, Context.ConnectionId);
            //_users.TryAdd(Context.ConnectionId, Context.ConnectionId);

            using (var scope = _logger.BeginScope("SCOPED_VALUE"))
            {
                _logger.LogInformation($"ConnectionId {Context.ConnectionId} connected.");

            }

            return base.OnConnectedAsync();
        }

        public override Task OnDisconnectedAsync(Exception exception)
        {
            string userUid;
            _hubDictionary.UsersDictionary.TryRemove(Context.ConnectionId, out userUid);

            using (var scope = _logger.BeginScope("SCOPED_VALUE"))
            {
                _logger.LogInformation($"UserUid {userUid} disconnected.");

            }


            return base.OnDisconnectedAsync(exception);
        }

        public void SetUserUid(string userUid)
        {
            _hubDictionary.UsersDictionary[Context.ConnectionId] = userUid;

            using (var scope = _logger.BeginScope("SCOPED_VALUE"))
            {
                _logger.LogInformation($"Connection {Context.ConnectionId} linked to userUid {userUid}");

            }

            //ClientNameChanged?.Invoke(Context.ConnectionId, userName);
        }
    }