Admin.Net中的消息通信SignalR解释
定义集线器接口
IOnlineUserHub
public interface IOnlineUserHub
{/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(object context);
}
实现集线器
OnlineUserHub
/// <summary>
/// 在线用户集线器
/// </summary>
[MapHub("/hubs/onlineUser")]
public class OnlineUserHub : Hub<IOnlineUserHub>
{private readonly IHubContext<OnlineUserHub, IOnlineUserHub> _hub;public OnlineUserHub(...,IHubContext<OnlineUserHub, IOnlineUserHub> hub){...// 注入 Hub_hub = hub;}// 有客户端通过SignalR连接过来, 把连接信息保存到数据库public override async Task OnConnectedAsync(){...... // 业务代码var user = new SysOnlineUser{ConnectionId = Context.ConnectionId,UserId = userId,UserName = account,RealName = realName,Time = DateTime.Now,Ip = httpContext.GetRemoteIpAddressToIPv4(true),TenantId = tenantId,};await _sysOnlineUerRep.InsertAsync(user); // 保存当前登录用户到数据库// 制作分组var groupName = $"{GROUP_ONLINE}{user.TenantId}";await this.Groups.AddToGroupAsync(Context.ConnectionId, groupName);// 推送消息给前端, 推送给一个分组await this.Clients.Groups(groupName).OnlineUserList(new OnlineUserList{RealName = user.RealName,Online = true,...});}// 客户端断开了public override async Task OnDisconnectedAsync(Exception exception){ ... }// 自定义方法public async Task ForceUserOffline(){...... // 业务代码// 推送消息给前端, 推送给指定的人await _hub.Clients.Client(input.ConnectionId).ForceOffline("强制下线");}
}
前端监听消息
import { signalR } from './signalR';onMounted(async () => {signalR.off('ForceOffline');// 关闭监听// 开始监听, 编写回调signalR.on('ForceOffline', async (data: any) => {// 收到这个消息, 把当前用户下线// 停止接收消息await signalR.stop(); // 告诉后端我下线了( 根据业务需要, 可以不用)await getAPI(SysAuthApi).apiSysAuthLogoutPost();// 清空本地Token (下线)clearAccessTokens();});
});
前端SignalR配置
signalR.ts
import * as SignalR from '@microsoft/signalr';
import { ElNotification } from 'element-plus';
import { getToken } from '/@/utils/axios-utils';// 初始化SignalR对象
const connection = new SignalR.HubConnectionBuilder().configureLogging(SignalR.LogLevel.Information).withUrl(`${window.__env__.VITE_API_URL}/hubs/onlineUser?token=${getToken()}`, { transport: SignalR.HttpTransportType.WebSockets, skipNegotiation: true }).withAutomaticReconnect({nextRetryDelayInMilliseconds: () => {return 5000; // 每5秒重连一次},}).build();connection.keepAliveIntervalInMilliseconds = 15 * 1000; // 心跳检测15s
connection.serverTimeoutInMilliseconds = 30 * 60 * 1000; // 超时时间30m// 启动连接
connection.start().then(() => {console.log('启动连接');
});
// 断开连接
connection.onclose(async () => {console.log('断开连接');
});
// 重连中
connection.onreconnecting(() => {ElNotification({title: '提示',message: '服务器已断线...',type: 'error',position: 'bottom-right',});
});
// 重连成功
connection.onreconnected(() => {console.log('重连成功');
});connection.on('OnlineUserList', () => {});export { connection as signalR };