SignalR连接异常:建立后立即断开,抛出Nullable值必填错误
SignalR连接立即断开,报错"Nullable object must have a value"
问题详情
连接启动后立刻断开,抛出以下错误:
Error: Connection disconnected with error ‘Error: Server returned an error on close: Connection closed with an error. InvalidOperationException: Nullable object must have a value.’
客户端代码(TypeScript)
public startConnection(): void { this.hubConnection = new HubConnectionBuilder() .withUrl(`${this.API_URL}/interviewRoundHub`).withAutomaticReconnect([5000]) .build(); if (this.hubConnection && this.hubConnection.state === "Disconnected") { this.hubConnection.start().then(() => { console.log('SignalR connection started.'); this.getStatus() //this.candidateList?.unshift(this.candidateList[0]); }).catch(error => { console.error('SignalR connection error:', error); }); } } getStatus(){ this.hubConnection?.on('FrontEndMethod', (assessmentStatus, candidateInviteId) => { console.log(assessmentStatus); console.log(candidateInviteId); this.message.assess = assessmentStatus; this.message.cand = candidateInviteId; this.receivedStatus.next(assessmentStatus); this.receivedCandidateId.next(candidateInviteId); this.message1.next(this.message) }); }
服务端代码(C#)
public override async Task OnConnectedAsync() { var currentUserId = _currentUser.GetId(); var currentUser = await _userManager.GetByIdAsync(currentUserId); var currentUserRoles = await _userManager.GetRolesAsync(currentUser); if (!_connectionsMap.Any(u => u.Key == currentUserId)) { _connectionsMap.Add(currentUserId, Context.ConnectionId); } if (currentUserRoles.Count > 0 && currentUserRoles.Any(x => x == _stringConstant.TeamAdmin)) { _teamAdminMap.Add(currentUserId, Context.ConnectionId); } return base.OnConnectedAsync(); } public override Task OnDisconnectedAsync(Exception exception) { var userId = _currentUser.GetId(); _connectionsMap.Remove(userId); if (_teamAdminMap.ContainsKey(userId)) { _teamAdminMap.Remove(userId); } return base.OnDisconnectedAsync(exception); }
解决方案
核心问题定位
错误InvalidOperationException: Nullable object must have a value源于代码尝试访问可空类型的Value属性,但该类型当前为null。结合服务端代码分析,大概率是_currentUser.GetId()返回了null,后续调用_userManager.GetByIdAsync(currentUserId)时,方法内部强制要求参数非空,触发异常导致SignalR连接被终止。
修复步骤
- 增加空值校验拦截:在
OnConnectedAsync方法开头验证currentUserId是否为空,若为空则直接终止无效连接:
public override async Task OnConnectedAsync() { var currentUserId = _currentUser.GetId(); // 新增空值校验,拦截未认证用户连接 if (currentUserId == null) { await Context.AbortAsync(); return; } var currentUser = await _userManager.GetByIdAsync(currentUserId); var currentUserRoles = await _userManager.GetRolesAsync(currentUser); if (!_connectionsMap.Any(u => u.Key == currentUserId)) { _connectionsMap.Add(currentUserId, Context.ConnectionId); } if (currentUserRoles.Count > 0 && currentUserRoles.Any(x => x == _stringConstant.TeamAdmin)) { _teamAdminMap.Add(currentUserId, Context.ConnectionId); } return base.OnConnectedAsync(); }
验证用户认证逻辑:检查
_currentUser的实现,确保只有已认证用户调用GetId()时才返回有效ID,未认证用户返回null,配合上述校验拦截无效连接请求。补充日志排查:可在空值校验处添加日志,方便追踪未认证用户的连接尝试:
if (currentUserId == null) { _logger.LogWarning("Unauthenticated user attempted to connect to InterviewRoundHub"); await Context.AbortAsync(); return; }
客户端优化(可选)
在连接失败的catch块中补充详细错误信息,便于前端排查:
.catch(error => { console.error('SignalR connection error:', error); console.error('Error details:', error.message, error.stack); });
内容的提问来源于stack exchange,提问作者Ashik Hussain
相关产品推荐
相关产品推荐

