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

SignalR中无法触发UnsubscribeFromProject,RemoveFromGroupAsync调用失败

SignalR中UnsubscribeFromProject方法无法触发的排查与解决

问题说明

已在SignalR Hub中实现SubscribeToProject和UnsubscribeFromProject方法,前端可正常调用SubscribeToProject完成群组订阅,但调用UnsubscribeFromProject时,Chrome开发者工具的WebSocket面板看不到请求发送,后端方法完全未触发。经调试确认前端代码已执行该调用,且参数已正确定义。

Hub后端代码

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging;
using OptTurnaroundApi.Repositories;
using OptTurnaroundApi.Services;
using System;
using System.Linq;
using System.Threading.Tasks;

namespace OptTurnaroundApi.Hubs
{
    [Authorize]
    public class MyHub : Hub
    {
        private readonly IUserRepository _userRepository;
        private readonly IAuthService _authService;
        private readonly ILogger<MyHub> _logger;


        public MyHub(IUserRepository userRepository, IAuthService authService, ILogger<MyHub> logger)
        {
            _userRepository = userRepository;
            _authService = authService;
            _logger = logger;
        }

        public async Task SubscribeToProject(string projectId)
        {
            var user = _userRepository.GetCurrentUser(true);

            try
            {
                await Groups.AddToGroupAsync(Context.ConnectionId, $"Project{projectId}");
            }
            catch (Exception ex)
            {
                _logger.LogWarning($"User {user.UserName} could not subscribe to project {projectId}: {ex.Message}");
            }
        }
        public async Task UnsubscribeFromProject(string projectId)
        {
            var user = _userRepository.GetCurrentUser(true);

            try
            {
                await Groups.RemoveFromGroupAsync(Context.ConnectionId, $"Project{projectId}");
            }
            catch (Exception ex)
            {
                _logger.LogWarning($"User {user.UserName} could not unsubscribe project {projectId}: {ex.Message}");
            }
        }

        public string GetConnectionId()
        {
            return Context.ConnectionId;
        }
    }
}

前端调用代码

const subscribeToNewProject = useCallback(
    ({ previousProjectId, connection }) => {
      // subscribe to new project when user changes project
      if (
        previousProjectId &&
        connection &&
        projectId &&
        previousProjectId !== projectId
      ) {
        // subscribe to a new project Id if the user changes project
        connection.invoke("SubscribeToProject", projectId.toString());
        connection.invoke(
          "UnsubscribeFromProject",
          previousProjectId.toString()
        );
        setPreviousProjectId(projectId);
      }
    },
    [projectId]
);

排查方案与解决步骤

1. 捕获Invoke的Promise异常

SignalR的connection.invoke返回Promise,若未处理异常,错误会被静默吞掉,导致看起来没有发送请求。当前代码未对两个invoke做错误捕获,是最可能的原因。

修改前端代码:

connection.invoke("SubscribeToProject", projectId.toString())
  .catch(err => console.error("订阅失败:", err));
connection.invoke("UnsubscribeFromProject", previousProjectId.toString())
  .catch(err => console.error("取消订阅失败:", err));

通过控制台日志查看具体错误信息,定位问题。

2. 校验参数格式一致性

确认previousProjectId.toString()生成的字符串,与Hub中拼接的Project{projectId}格式完全匹配。例如是否存在数字转字符串后带引号、前后空格等差异,导致群组名称不匹配。

添加日志验证:

console.log("待取消订阅的群组:", `Project${previousProjectId.toString()}`);
console.log("待订阅的群组:", `Project${projectId.toString()}`);

3. 检查方法名大小写匹配

SignalR默认对方法名大小写敏感,确认前端调用的"UnsubscribeFromProject"与Hub中的方法名UnsubscribeFromProject完全一致,避免因大小写差异导致方法无法匹配。

4. 验证连接状态

调用前检查连接是否处于正常连接状态,避免因连接断开/重连导致调用失效:

if (connection.state === signalR.HubConnectionState.Connected) {
  connection.invoke("SubscribeToProject", projectId.toString())
    .catch(err => console.error("订阅失败:", err));
  connection.invoke("UnsubscribeFromProject", previousProjectId.toString())
    .catch(err => console.error("取消订阅失败:", err));
} else {
  console.error("SignalR连接未处于已连接状态");
}

5. 修复后端异常捕获范围

Hub的UnsubscribeFromProject方法中,GetCurrentUser调用未被包含在try块内,若该方法抛出异常,会直接导致整个方法失败,但错误未被捕获记录。

修改后端代码:

public async Task UnsubscribeFromProject(string projectId)
{
    try
    {
        var user = _userRepository.GetCurrentUser(true);
        await Groups.RemoveFromGroupAsync(Context.ConnectionId, $"Project{projectId}");
    }
    catch (Exception ex)
    {
        _logger.LogWarning($"用户取消项目{projectId}订阅失败: {ex.Message}");
        throw; // 抛出异常让前端捕获
    }
}

内容的提问来源于stack exchange,提问作者meerkat

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 04:20:22