当前位置: 首页 > news >正文

.net 6 signalr

1)Startup.cs

 //添加 SignalR 服务services.AddSignalR();// 添加 CORS 策略(允许前端访问)services.AddCors(options =>{options.AddPolicy("AllowAll", builder =>{builder.WithOrigins(AppsettingsEntity.allowCors) // 前端地址.AllowAnyHeader().AllowAnyMethod().AllowCredentials(); // SignalR 必须允许凭证});});// 启用 CORS(一定要放在 UseRouting 之后,UseEndpoints 之前)app.UseCors("AllowAll");app.UseEndpoints(endpoints =>
{endpoints.MapControllers();// 注册 ChatHubendpoints.MapHub<ChatHub>("/chathub").RequireCors("AllowAll"); // Hub 也要应用 CORS 策略
});

2)ChatHub.cs

using Common.PlatformEnum;
using Microsoft.AspNetCore.SignalR;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;namespace Platform.Api.Hubs
{public class ChatHub : Hub{// 存储用户与连接ID的映射(一个用户可能有多个连接,比如多个浏览器标签页)private static readonly ConcurrentDictionary<string, HashSet<string>> _userConnections = new();// 当用户连接上时触发public override Task OnConnectedAsync(){var user = Context.GetHttpContext()?.Request.Query["user"];if (!string.IsNullOrEmpty(user)){_userConnections.AddOrUpdate(user!,_ => new HashSet<string> { Context.ConnectionId },(_, connections) =>{connections.Add(Context.ConnectionId);return connections;});}return base.OnConnectedAsync();}// 当用户断开连接时触发public override Task OnDisconnectedAsync(Exception? exception){foreach (var kvp in _userConnections){if (kvp.Value.Contains(Context.ConnectionId)){Logout(kvp.Key);kvp.Value.Remove(Context.ConnectionId);if (kvp.Value.Count == 0)_userConnections.TryRemove(kvp.Key, out _);break;}}return base.OnDisconnectedAsync(exception);}// 向所有人发送(原始示例)public async Task SendMessage(string user, string message){await Clients.All.SendAsync("ReceiveMessage", user, message);}// 向指定用户发送消息public async Task SendMessageToUser(string toUser, string formUser, SignalrEnum signalrEnum, string message){if (_userConnections.TryGetValue(toUser, out var connections)){foreach (var connectionId in connections){await Clients.Client(connectionId).SendAsync("ReceiveMessage", formUser,(int)signalrEnum, message);}}}/// <summary>/// 学生进入竞赛场次/// </summary>/// <param name="formUser">学生signalr用户标识</param>/// <returns></returns>public async Task StudentLogin(string formUser){string[] userSplit = formUser.Split('_');string session = userSplit[0];var _userConnection = _userConnections.FirstOrDefault(a => a.Key.StartsWith($"{session}_t"));if (_userConnection.Key != null){string toUser = _userConnection.Key;await SendMessageToUser(toUser, formUser, SignalrEnum.学生进入竞赛场次, $"{formUser}进入竞赛场次");}}/// <summary>/// 老师进入竞赛场次/// </summary>/// <param name="formUser">老师signalr用户标识</param>/// <returns></returns>public async Task TeacherLogin(string formUser){string[] userSplit = formUser.Split('_');string session = userSplit[0];var _tempUserConnections = _userConnections.Where(a => a.Key.StartsWith($"{session}_s"));string studentids = string.Join(",", _tempUserConnections.Select(a => a.Key.Split('_')[2]));await SendMessageToUser(formUser, formUser, SignalrEnum.老师进入竞赛场次, studentids);}/// <summary>/// 学生离开竞赛场次/// </summary>/// <param name="formUser">学生signalr用户标识</param>/// <returns></returns>public async Task Logout(string formUser){string[] userSplit = formUser.Split('_');string session = userSplit[0];string type = userSplit[1];if (type == "s"){var _userConnection = _userConnections.FirstOrDefault(a => a.Key.StartsWith($"{session}_t"));if (_userConnection.Key != null){string toUser = _userConnection.Key;await SendMessageToUser(toUser, formUser, SignalrEnum.学生离开竞赛场次, $"{formUser}离开竞赛场次");}}}/// <summary>/// 收卷/// </summary>/// <param name="formUser">老师signalr用户标识</param>/// <param name="toUserId">学生数据库主键,如果是多个用英文逗号隔开</param>/// <returns></returns>public async Task Finish(string formUser, string toUserId){string[] userSplit = formUser.Split('_');string session = userSplit[0];if (string.IsNullOrEmpty(toUserId)){//全场收卷var _tempUserConnections = _userConnections.Where(a => a.Key.StartsWith($"{session}_s"));foreach (var _userConnection in _tempUserConnections){string toUser = _userConnection.Key;await SendMessageToUser(toUser, formUser, SignalrEnum.收卷, $"{formUser}收卷");}}else{//单个收卷foreach (string touserid in toUserId.Split(',')){var _userConnection = _userConnections.FirstOrDefault(a => a.Key.StartsWith($"{session}_s_{touserid}"));if (_userConnection.Key != null){string toUser = _userConnection.Key;await SendMessageToUser(toUser, formUser, SignalrEnum.收卷, $"{formUser}收卷");}}}}/// <summary>/// 延迟/// </summary>/// <param name="formUser">老师signalr用户标识</param>/// <param name="toUserId">学生数据库主键,如果是多个用英文逗号隔开</param>/// <returns></returns>public async Task Delay(string formUser, string toUserId){string[] userSplit = formUser.Split('_');string session = userSplit[0];if (string.IsNullOrEmpty(toUserId)){//全场延迟var _tempUserConnections = _userConnections.Where(a => a.Key.StartsWith($"{session}_s"));foreach (var _userConnection in _tempUserConnections){string toUser = _userConnection.Key;await SendMessageToUser(toUser, formUser, SignalrEnum.延迟, $"{formUser}延迟");}}else{//单个延迟foreach (string touserid in toUserId.Split(',')){var _userConnection = _userConnections.FirstOrDefault(a => a.Key.StartsWith($"{session}_s_{touserid}"));if (_userConnection.Key != null){string toUser = _userConnection.Key;await SendMessageToUser(toUser, formUser, SignalrEnum.延迟, $"{formUser}延迟");}}}}}
}

3)老师端

<script src="signalr.min.js"></script>
<script>// 当前用户标识(CompetitionSessionId_t_UserId)// 场次1_老师_老师1const currentUser = "p1_t_t1";// 建立连接时,把 user 作为参数传给后端const connection = new signalR.HubConnectionBuilder()// .withUrl(`http://47.111.227.47:8082/chathub?user=${currentUser}`).withUrl(`http://localhost:8082/chathub?user=${currentUser}`).build();// 接收消息事件connection.on("ReceiveMessage", (user, type, message) => {console.log(`收到来自 ${user} 的消息: signalr操作类型:${type},内容:${message}`);});// 启动连接connection.start().then(() => {console.log("已连接 SignalR Hub 作为用户:", currentUser);// 老师进入竞赛场次connection.invoke("TeacherLogin", currentUser).catch(console.error);}).catch(console.error);// 全场收卷function finish() {connection.invoke("Finish", currentUser, '').catch(console.error);}// 单个收卷(如果是多个用英文逗号隔开)function singleFinish() {connection.invoke("Finish", currentUser, 's1,s2').catch(console.error);}// 全场延迟function delay() {connection.invoke("Delay", currentUser, '').catch(console.error);}// 单个延迟(如果是多个用英文逗号隔开)function singlDelay() {connection.invoke("Delay", currentUser, 's1').catch(console.error);}
</script>
场次1_老师_老师1
<button onclick="finish()">全场收卷</button>
<button onclick="singleFinish()">单收卷</button>
<button onclick="delay()">全场延时</button>
<button onclick="singlDelay()">单个延时</button>

4)学生端

<script src="signalr.min.js"></script>
<script>// 当前用户标识(CompetitionSessionId_s_CompetitionUserId)// 场次1_学生_学生1const currentUser = "p1_s_s1";// 建立连接时,把 user 作为参数传给后端const connection = new signalR.HubConnectionBuilder().withUrl(`http://localhost:8082/chathub?user=${currentUser}`).build();// 接收消息事件connection.on("ReceiveMessage", (user, type, message) => {console.log(`收到来自 ${user} 的消息: signalr操作类型:${type},内容:${message}`);});// 启动连接connection.start().then(() => {console.log("已连接 SignalR Hub 作为用户:", currentUser);// 学生进入竞赛场次connection.invoke("StudentLogin", currentUser).catch(console.error);}).catch(console.error);
</script>
场次1_学生_学生1

http://www.dtcms.com/a/474694.html

相关文章:

  • 从零到一:基于.NET 9.0构建企业级AI智能体对话平台的实战之旅
  • 网站建设费用标准wordpress 只剩纯文本
  • mysql基础【函数 与 约束】
  • 昆明免费建站模板玉石网站建设的定位
  • 什么视频网站可以做链接地址新闻发稿114
  • 重庆网站建设模板制作蒙自做网站的公司
  • 什么是web前端?
  • Win10,在ESP分区添加PE系统,隐藏VTOYEFI分区
  • Qwen3(通义千问3)、OpenAI GPT-5、DeepSeek 3.2、豆包最新模型(Doubao 4.0)通用模型能力对比
  • 小学做试卷的网站wordpress跳转页面
  • 外国设计网站推荐网页制作作业下载
  • JavaScript入门分享_JavaScript日常处理
  • layui 企业网站模板域名注册服务商网站
  • Linux 文件描述符详解
  • Petrel三维地质建模02
  • 做网站建设涉及哪些算法重庆品牌网站建设公司
  • 婚庆公司网站源码深圳企业网查询
  • Obsidian-1.8.10下载安装(附安装包)
  • T527 RTL8211F_JL2101B-N040C 以太网PHY调试
  • Docker 镜像进阶维护:MySQL 数据、配置与日志的宿主机持久化方案
  • FDConv:频率动态卷积在密集图像预测中的突破性进展
  • 消防有哪些网站合适做网站下面版权代码
  • SQLSugar和EF框架的区别
  • 我的网站模板初学者自己做网站
  • 前端工程师是做网站吗网站源码运行
  • 【C语言实战(14)】深入C语言函数基础:从理论到实战
  • 基础算法:二分查找
  • 深度学习入门(四)——从激活到注意力:神经网络的现代模块与工程实践
  • Linux下的压缩(zip)解压(unzip)缩命令
  • 湖南平台网站建设推荐dedecms网站如何上线