Admin.Net中的消息通信SignalR解释

定义集线器接口

IOnlineUserHub

csharp 复制代码
public interface IOnlineUserHub
{
    /// 在线用户列表
    Task OnlineUserList(OnlineUserList context);

    /// 强制下线
    Task ForceOffline(object context);

    /// 发布站内消息
    Task PublicNotice(SysNotice context);

    /// 接收消息
    Task ReceiveMessage(object context);
}

实现集线器

OnlineUserHub

csharp 复制代码
/// <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("强制下线");
	}
}

前端监听消息

js 复制代码
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

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 };
相关推荐
曹振华9 天前
.net 6 signalr
.net·signalr
爱吃香蕉的阿豪3 个月前
SignalR 全解析:核心原理、适用场景与 Vue + .NET Core 实战
vue.js·microsoft·c#·.netcore·signalr
csdn_aspnet4 个月前
使用 .NET Core 7 SignalR 构建实时聊天应用程序
signalr·.net7
csdn_aspnet4 个月前
.NET 9.0 SignalR 支持修剪和原生 AOT
aot·signalr·.net9
csdn_aspnet6 个月前
使用 SignalR 在 .NET Core 8 最小 API 中构建实时通知
signalr·.net8
csdn_aspnet7 个月前
在 .NET 8 中使用自定义令牌身份验证掌握 SignalR Hub 安全性
signalr·.net8
lixww.cn8 个月前
ASP.NET Core SignalR向部分客户端发消息
javascript·websocket·vue·asp.net core·signalr
lixww.cn8 个月前
ASP.NET Core SignalR的协议协商
asp.net core·signalr
lixww.cn8 个月前
ASP.NET Core SignalR的分布式部署
redis·消息队列·asp.net core·signalr