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

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连接被终止。

修复步骤

  1. 增加空值校验拦截:在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();
}
  1. 验证用户认证逻辑:检查_currentUser的实现,确保只有已认证用户调用GetId()时才返回有效ID,未认证用户返回null,配合上述校验拦截无效连接请求。

  2. 补充日志排查:可在空值校验处添加日志,方便追踪未认证用户的连接尝试:

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 02:47:05