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
相关产品推荐
相关产品推荐

