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

【ASP.NET CORE】 11. SignalR

本系列专栏基于杨中科老师的《ASP.NET Core技术内幕与项目 实战》本人记录梳理的学习笔记有部分的增补和省略。更全面系统的讲解请看杨老师的视频课【.NET教程.Net Core视频教程杨中科主讲】。一、服务器向客户端推送数据1. 传统方案长轮询原理客户端发起请求→服务器阻塞请求直到有数据 / 超时→客户端收到响应后立即发起新请求循环往复。缺点频繁 HTTP 请求 / 响应开销大、延迟高、并发能力弱仅作为降级方案。2. WebSocket现代实时通信标准基于TCP 协议支持二进制 文本双工通信客户端和服务器可双向主动发送数据。性能优势一次握手持久连接开销远小于长轮询并发能力大幅提升。部署特点独立于 HTTP 协议但复用 HTTP 服务器端口 借助 HTTP 完成初始握手无需单独端口兼容性更强。局限原生 API 繁琐需手动处理连接、重连、序列化、兼容降级等问题。3. ASP.NET Core SignalRWebSocket 高级封装定位.NET Core 平台下实时通信的一站式解决方案自动适配通信方式优先 WebSocket降级 SSE / 长轮询。核心概念Hub集线器→ 实时通信的数据交换中心统一管理客户端连接、消息分发、组管理。优势简化 API、自动重连、依赖注入友好、支持分布式部署、集成身份认证。二、SignalR 项目搭建核心流程创建 Web API 服务端 → 配置 SignalR 与跨域 → 编写 Hub 集线器 → Vue 前端接入 → 实现全员消息推送。1. 服务端开发1环境准备创建ASP.NET Core Web API项目无需额外安装基础 NuGet 包ASP.NET Core 内置 SignalR。2编写 Hub 集线器Hub 是消息处理核心继承自Hub基类定义客户端可调用的方法/// summary /// 聊天室集线器客户端通过此Hub与服务端通信 /// /summary public class ChatRoomHub : Hub { /// summary /// 发送公共消息全员接收 /// 客户端通过Invoke调用此方法 /// /summary /// param namemessage客户端发送的消息内容/param public Task SendPublicMessage(string message) { // 获取当前客户端的唯一连接ID string connId this.Context.ConnectionId; string msg ${connId} {DateTime.Now}: {message}; // 向所有连接的客户端推送消息客户端监听ReceivePublicMessage事件 return Clients.All.SendAsync(ReceivePublicMessage, msg); } }3注册 SignalR 与跨域配置SignalR 基于浏览器跨域策略必须配置 CORS否则前端无法连接var builder WebApplication.CreateBuilder(args); builder.Services.AddControllers(); // 1. 注册SignalR服务 builder.Services.AddSignalR(); // 2. 配置跨域策略允许前端地址访问 string[] urls new[] { http://localhost:3000 }; // 前端Vue运行地址 builder.Services.AddCors(options { options.AddDefaultPolicy(policy { policy.WithOrigins(urls) // 允许的源 .AllowAnyMethod() // 允许所有请求方法 .AllowAnyHeader() // 允许所有请求头 .AllowCredentials(); // 允许携带凭据Cookie/Token必选 }); }); var app builder.Build(); // 启用中间件顺序不能错 app.UseCors(); // 启用跨域 app.UseHttpsRedirection(); app.UseAuthorization(); // 3. 映射Hub端点客户端通过此地址连接SignalR app.MapHubChatRoomHub(/Hubs/ChatRoomHub); app.MapControllers(); app.Run();2. 前端开发Vue31安装客户端 SDKnpm install microsoft/signalr2编写实时聊天组件template div !-- 消息输入框回车发送 -- input typetext v-modelstate.userMessage keypresshandleKeyPress placeholder输入消息回车发送 / !-- 消息列表 -- ul li v-for(msg, index) in state.messages :keyindex {{ msg }} /li /ul /div /template script setup import { reactive, onMounted } from vue; import * as signalR from microsoft/signalr; // 响应式数据 const state reactive({ userMessage: , // 输入框消息 messages: [] // 消息列表 }); let connection; // SignalR连接对象 // 页面挂载后建立SignalR连接 onMounted(async () { // 1. 配置连接 connection new signalR.HubConnectionBuilder() .withUrl(https://localhost:7112/Hubs/ChatRoomHub) // 服务端Hub地址 .withAutomaticReconnect() // 自动重连断线自动恢复 .build(); // 2. 监听服务端推送的公共消息 connection.on(ReceivePublicMessage, (msg) { state.messages.push(msg); }); // 3. 启动连接 try { await connection.start(); console.log(SignalR连接成功); } catch (err) { console.error(连接失败, err); } }); // 回车发送消息 const handleKeyPress async (e) { if (e.keyCode ! 13) return; // 非回车直接返回 if (!state.userMessage.trim()) return; // 调用服务端Hub的SendPublicMessage方法 await connection.invoke(SendPublicMessage, state.userMessage); state.userMessage ; // 清空输入框 }; /script三、集群部署1. 协议协商问题当 SignalR 部署在服务器集群时会出现协议协商失败第一步客户端发起协商请求被服务器 A 处理第二步后续 WebSocket 请求被负载均衡转发到服务器 B结果连接丢失通信失败。2. 解决方案方案 1粘性会话原理负载均衡配置会话绑定同一客户端的所有请求强制转发到同一台服务器。缺点公网 IP 共享会导致负载不均集群扩容适应性差无法灵活弹性伸缩。方案 2禁用协商推荐直接强制使用 WebSocket 协议跳过协商步骤一次连接绑定单台服务器无需依赖负载均衡配置。优点简单高效无粘性会话缺陷缺点无法降级到 SSE / 长轮询现代浏览器均支持 WebSocket几乎无影响。前端修改代码// 配置跳过协商 仅使用WebSocket const transportOptions { skipNegotiation: true, transport: signalR.HttpTransportType.WebSockets }; connection new signalR.HubConnectionBuilder() .withUrl(https://localhost:7047/Hubs/ChatRoomHub, transportOptions) .withAutomaticReconnect() .build();四、分布式部署1. 跨服务器消息同步问题集群中 4 个客户端分别连接服务器 A、BA 服务器的消息无法推送给连接 B 的客户端消息仅在单服务器内广播。2. 解决方案Redis 背板所有服务器连接同一个 Redis通过 Redis 做消息中转实现跨服务器消息同步。实施步骤安装 NuGet 包Install-Package Microsoft.AspNetCore.SignalR.StackExchangeRedis注册 Redis 背板builder.Services.AddSignalR() // 配置Redis连接字符串 通道前缀区分项目 .AddStackExchangeRedis(127.0.0.1:6379, options { options.Configuration.ChannelPrefix MyChatApp_; });原理服务端发送消息→写入 Redis→所有服务器订阅 Redis 消息→分发给自身连接的客户端实现全局广播。五、身份认证1. JWT集成问题默认 SignalR 无权限控制任何人可连接 Hub需集成 JWT 实现登录后访问。2. 服务端配置1定义 JWT 配置类/// summary /// JWT配置参数从appsettings.json读取 /// /summary public class JWTOptions { public string SigningKey { get; set; } // 密钥 public int ExpireSeconds { get; set; } // 过期时间 }2appsettings.json 配置JWT: { SigningKey: YourSecretKey1234567890123456, // 长度≥16位 ExpireSeconds: 86400 // 1天过期 }3注册 JWT 认证// 绑定JWT配置 services.ConfigureJWTOptions(builder.Configuration.GetSection(JWT)); // 注册JWT认证 services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(x { var jwtOpt builder.Configuration.GetSection(JWT).GetJWTOptions(); var keyBytes Encoding.UTF8.GetBytes(jwtOpt.SigningKey); var secKey new SymmetricSecurityKey(keyBytes); // Token验证规则 x.TokenValidationParameters new TokenValidationParameters { ValidateIssuer false, ValidateAudience false, ValidateLifetime true, ValidateIssuerSigningKey true, IssuerSigningKey secKey }; // 关键SignalR通过URL参数传递TokenWebSocket不支持请求头 x.Events new JwtBearerEvents { OnMessageReceived context { // 从URL的access_token参数获取Token var accessToken context.Request.Query[access_token]; var path context.HttpContext.Request.Path; // 匹配Hub地址则赋值Token if (!string.IsNullOrEmpty(accessToken) path.StartsWithSegments(/Hubs/ChatRoomHub)) { context.Token accessToken; } return Task.CompletedTask; } }; });4启用认证中间件// 顺序认证 → 授权 app.UseAuthentication(); // 新增 app.UseAuthorization();5Hub 添加权限校验在 Hub 类上添加[Authorize]特性未登录用户无法连接[Authorize] // 必须登录才能访问此Hub public class ChatRoomHub : Hub { // ... }6编写登录接口[ApiController] [Route(api/[controller])] public class AccountController : ControllerBase { private readonly IOptionsJWTOptions _jwtOptions; public AccountController(IOptionsJWTOptions jwtOptions) { _jwtOptions jwtOptions; } [HttpPost(login)] public IActionResult Login(string username, string password) { // 省略用户名密码校验 var userId 1001; // 实际从数据库获取 var claims new[] { new Claim(ClaimTypes.NameIdentifier, userId), // 用户唯一ID定向推送用 new Claim(ClaimTypes.Name, username) // 用户名 }; // 生成Token var key new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtOptions.Value.SigningKey)); var creds new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var token new JwtSecurityToken( expires: DateTime.Now.AddSeconds(_jwtOptions.Value.ExpireSeconds), signingCredentials: creds, claims: claims ); return Ok(new { Token new JwtSecurityTokenHandler().WriteToken(token) }); } }3. 前端携带 Token 连接// 登录后获取Token const startConnection async (token) { const options { skipNegotiation: true, transport: signalR.HttpTransportType.WebSockets, accessTokenFactory: () token // 自动携带Token到URL }; connection new signalR.HubConnectionBuilder() .withUrl(https://localhost:7047/Hubs/ChatRoomHub, options) .withAutomaticReconnect() .build(); await connection.start(); };六、定向推送SignalR 支持三种筛选方式满足私聊、分组、全员推送场景ConnectionId单个客户端连接 IDGroups客户端分组如房间、部门UserId用户唯一 ID对应ClaimTypes.NameIdentifier。实战用户私聊1. 服务端 Hub 方法/// summary /// 发送私信指定用户接收 /// /summary /// param namedestUserName目标用户名/param /// param namemessage消息内容/param public async Taskstring SendPrivateMessage(string destUserName, string message) { // 1. 根据用户名查询目标用户ID实际从数据库获取 string destUserId await _userService.GetUserIdByNameAsync(destUserName); // 2. 获取当前登录用户信息 string srcUserName this.Context.User.FindFirst(ClaimTypes.Name)!.Value; string time DateTime.Now.ToShortTimeString(); // 3. 向指定用户ID推送消息 await Clients.User(destUserId).SendAsync(ReceivePrivateMessage, srcUserName, time, message); return 发送成功; }2. 前端调用与监听// 发送私信 const sendPrivate async (destUserName, msg) { await connection.invoke(SendPrivateMessage, destUserName, msg); }; // 监听私信 connection.on(ReceivePrivateMessage, (srcUser, time, msg) { state.messages.push(${srcUser} ${time} 私信${msg}); });核心 API服务端 API作用Clients.All全员推送Clients.User(userId)指定用户推送Clients.Client(connId)指定连接推送Clients.Others排除自己全员推送Groups.AddToGroupAsync加入分组Groups.RemoveFromGroupAsync退出分组Clients.Group(groupName)分组推送总结SignalR封装 WebSocket 细节自动适配通信方式零成本实现实时推送Hub 为核心配置跨域 映射端点前端通过 SDK 连接支持用户、连接、分组三种维度满足私聊 / 分组 / 全员场景。集群 / 分布式禁用协商解决协议问题Redis 背板实现跨服务器消息同步。安全控制JWT 集成通过 URL 参数传递 Token[Authorize]校验权限。

相关文章:

【ASP.NET CORE】 11. SignalR

本系列专栏基于杨中科老师的《ASP.NET Core技术内幕与项目 实战》,本人记录梳理的学习笔记,有部分的增补和省略。更全面系统的讲解,请看杨老师的视频课:【.NET教程,.Net Core视频教程,杨中科主讲】。 一、…...

openclaw本地部署实践复盘 openclaw本地部署案例分享 openclaw本地部署亲测记录 openclaw本地部署实践分享 openclaw本地部署经验复盘 openc

在 openclaw本地部署 的实际项目推进中,环境依赖复杂、权限控制难统一以及插件生态缺乏标准化管理,往往成为工程团队普遍面临的技术挑战。围绕这一问题,行业中通常会通过更系统化的架构设计与部署流程来降低不确定性,北京万维速达…...

mac M芯片安装pytorch

用 conda 创建一个 arm64 的 Python 环境 在这个 conda 环境里用 pip 安装 PyTorch 用 MPS 验证是否启用了 Apple GPU 这是因为 PyTorch 官方当前在 macOS 上推荐的包管理方式是 pip,并注明最新稳定版要求 Python 3.10;macOS 安装页也直接给出了 pip3 in…...

灭菌柜集中监控管理平台解决方案

某工厂要求对研发实验室的多个灭菌柜进行集中监控与在线管理,需要监控的数据量包括干燥开始时间/结束时间、灭菌开始时间/结束时间、升温开始时间/结束时间等,便于统计实验结果与设备性能。对此,通过本地部署数据中台,能够实现多个…...

重置root密码!

mountmount -o remount,rw /sysroot(这里需要注意空格哦!!!)chroot /sysrootpasswd输入新密码,输入的时候没有提示的哦再次输入设置的新密码touch /.autorelableexitexit注意哦,小编改的是root用…...

JavaScript性能优化实战迸礁

JavaScript性能优化实战技术文章大纲 性能优化的核心原则 减少代码执行时间 降低内存占用 优化网络请求 提升用户体验 代码层面的优化 避免全局变量污染,使用模块化或闭包 减少DOM操作,批量更新或使用文档片段 使用事件委托减少事件监听器数量 优化循环结…...

JavaScript性能优化实战枚徽

JavaScript性能优化实战技术文章大纲 性能优化的核心原则 减少代码执行时间 降低内存占用 优化网络请求 提升用户体验 代码层面的优化 避免全局变量污染,使用模块化或闭包 减少DOM操作,批量更新或使用文档片段 使用事件委托减少事件监听器数量 优化循环结…...

第3章 矩阵:系统、变换与结构的表达

底层数学四部曲第四部 线性代数:入门与全领域展开 第3章 矩阵:系统、变换与结构的表达 矩阵的本质,是线性关系的“容器”,是向量变换的“规则”,是复杂系统的“浓缩表达”。 上一章我们掌握了向量——线性世界的基本单…...

Thinkphp和Laravel框架都支持基于小程序的民宿预订系统-web pc 手机端

目录ThinkPHP与Laravel框架实现多端民宿预订系统的方案技术选型与架构设计核心功能模块实现数据库设计要点性能优化策略部署与监控跨端适配方案安全防护措施项目技术支持可定制开发之功能创新亮点源码获取详细视频演示 :文章底部获取博主联系方式!同行可…...

《C++实战项目-高并发内存池》8. 最终性能优化与测试

💡Yupureki:个人主页 ✨个人专栏:《C》 《算法》《Linux系统编程》《高并发内存池》 🌸Yupureki🌸的简介: 目录 1. 使用基数树进行优化 2. 性能测试 完整项目链接https://github.com/Yupureki-code/ConcurrentMemoryPool 1. 使用基数树进行…...

网络安全--Windows操作系统

(新手小白入门网络安全,学习Windows操作系统基础知识,如有错误,欢迎批评指正!)一、初识操作系统操作系统(Operating System,简称OS)是管理和控制计算机硬件与软件资源的计…...

刷招聘软件时的迟疑?AI大模型才是程序员的新底气

刷着招聘APP的你,是否也曾突然陷入迟疑? 屏幕上密密麻麻的“大模型工程师”“AIGC应用开发工程师”岗位,技能要求写得愈发细致具体,从模型微调、Prompt工程到落地部署,条条直指AI领域。反观自己简历上引以为傲的“微服…...

2026 AI风口下,普通人(含程序员/小白)可落地的高薪岗位指南

国家统计局1月19日最新发布的数据,相信不少人都刷到了:2025年全国居民人均可支配收入达43377元,同比增长5.0%。这个数字看似稳健增长,但懂行的人都清楚,收入差距正被新一轮行业风口悄悄拉大,而2026年最具爆…...

从零开始构建Agentic RAG系统:LangGraph+Qwen打造智能自适应RAG

本文详细介绍Agentic RAG系统的构建方法,该系统融合动态查询分析和自我纠错机制,能够根据查询复杂度自适应选择检索与生成策略。文章基于LangGraph和Qwen模型,从状态管理、查询路由、文档检索、网络搜索到幻觉检测等11个步骤,完整…...

‌智慧校园系统价格解析:如何看懂报价背后的逻辑与选择适合自己的方案?

✅作者简介:合肥自友科技 📌核心产品:智慧校园平台(包括教工管理、学工管理、教务管理、考务管理、后勤管理、德育管理、资产管理、公寓管理、实习管理、就业管理、离校管理、科研平台、档案管理、学生平台等26个子平台) 。公司所有人员均有多…...

别再死磕 Python 了!这 4 款低代码工具也能做深度数据分析!

目录 一、FineBI 二、活字格 BI 插件 三、钉钉宜搭 QuickBI 四、Power BI 五、工具总结与对比 常见问答 想用数据驱动业务,却被代码给困住了? 业务那边急着要数据,你还在和Python库的版本兼容问题较劲……卡在脚本报错里寸步难行。 …...

计科-Linux4-中文件查看命令的详细介绍「整理」

...

妥妥的豪华局 —— 让 AI 来做照片分析

虽然 AI 无法给出所有的准确分析。 尝试使用 AI 分析一张照片,照片上的不少细节 AI 都注意到了,尤其是对中美使用餐具的情况做了对比。 同时,口味判断是准确的。 同时,给出的照片中,删除了所有的 EXIF 信息&#xff…...

静止同步调相机——01 无功补偿原理

无功补偿原理...

黄金悖论:无用的巅峰

“僭越者”的冠冕:黄金的终极悖论这一次,黄金的暴涨显得如此理所当然,甚至带着一丝命定的傲慢。然而,在其君临天下的价格曲线之下,涌动着一个深刻而古老的悖论:它正因其“无用”,而达至了“大用…...

仓库管理五大法:收、管、存、发、盘

目录 头条标题:仓库管理必看:收、管、存、发、盘5大方法 一、收:入库管理,把好物料入口关 1、单据到达 2、实物核对 3、办理入库 4、信息更新 二、管:在库管理,做好物料日常管控 1、分区分类 2、货…...

基于有源阻尼的PMSM高阻尼复矢量电流控制仿真、有参考文献

✅作者简介:热爱科研的Matlab仿真开发者,擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室🍊个人信条:格物致知,完整Matlab代码及仿真咨询…...

【独家原创】基于(蜜獾算法)HBA-Transformer单变量时序预测(单输入单输出) Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室🍊个人信条:格物致知,完整Matlab代码及仿真咨询…...

【独家原创】基于(黏菌算法)SMA-Transformer多变量回归预测(多输入单输出) Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…...

基于DE-Transformer多变量时序预测 (多输入单输出)Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…...

【路径规划】基于Q-Learning实现的多机器人路径规划演示附matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…...

风电SCADA数据采集物联网解决方案

风电SCADA能够实时采集风电机组的运行数据,并对风力发电机组进行监视和控制,确保风电场安全高效地运行。现要求将SCADA数据采集到云服务器中,实现远程化的管理和应用。对此,物通博联(WideIOT)提供高效可靠的…...

并行算法在STL中的应用

1、非修改序列算法这些算法不会改变它们所操作的容器中的元素。1.1 find 和 find_iffind(begin, end, value):查找第一个等于 value 的元素,返回迭代器(未找到返回 end)。find_if(begin, end, predicate):查找第一个满…...

基于DE-Transformer单变量时序预测 (单输入单输出)Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…...

【数据分析】数据驱动预测控制策略的比较分析附matlab代码复现

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…...