SignalR实现SQL数据实时广播问题:仅页面加载时生效
问题修复:数据库变更时SignalR实时推送通知
问题分析
当前代码仅在页面加载时触发一次数据查询和通知,数据库后续变更无法触发推送,核心原因包括:
SqlDependency触发变更后会自动失效,未重新创建新的依赖订阅- 数据库查询逻辑存在潜在风险(如未判断数据读取结果、连接管理不严谨)
- 未处理SignalR连接断开后的重连场景
修复步骤及代码调整
1. 调整Hub文件(NotificationHub.cs)
namespace SignalR { [HubName("notificationHub")] public class NotificationHub : Hub { [HubMethodName("sendNotifications")] public void SendNotifications() { string namePrint = string.Empty; string connectionString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString; using (var connection = new SqlConnection(connectionString)) { string query = "select Name_print from Print_Name_Machine where User_ID = '123'"; connection.Open(); using (SqlCommand command = new SqlCommand(query, connection)) { // 重置通知配置,确保每次创建新的SqlDependency command.Notification = null; SqlDependency dependency = new SqlDependency(command); dependency.OnChange += Dependency_OnChange; using (SqlDataReader dr = command.ExecuteReader()) { // 读取数据前先判断是否有有效结果 if (dr.HasRows && dr.Read()) { namePrint = dr["Name_print"].ToString(); } } } } // 获取Hub上下文并推送最新数据到所有客户端 IHubContext context = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>(); context.Clients.All.recieveNotification(namePrint); } private void Dependency_OnChange(object sender, SqlNotificationEventArgs e) { // 仅处理合法的变更事件,排除无效通知 if (e.Type == SqlNotificationType.Change && e.Info != SqlNotificationInfo.Invalid) { // 重新订阅依赖并推送最新数据 SendNotifications(); // 移除旧的事件绑定,避免内存泄漏 ((SqlDependency)sender).OnChange -= Dependency_OnChange; } } } }
2. 启用SQL Server Service Broker
SqlDependency依赖SQL Server的Service Broker功能,需执行以下SQL命令启用:
ALTER DATABASE [你的数据库名称] SET ENABLE_BROKER WITH ROLLBACK IMMEDIATE;
3. 客户端代码优化(Index.cshtml)
添加连接重连逻辑,确保客户端断开后自动恢复连接:
@*@{ ViewBag.Title = "Home Page"; }*@ <div class="row"> <h1>Broadcast Realtime SQL data using SignalR</h1> <div> <p>You have <span id="spanNewMessages">0</span> New Message Notification.</p> </div> </div> @section scripts { <script src="~/Scripts/jquery.signalR-2.4.3.js"></script> <script src="~/signalr/hubs"></script> <script type="text/javascript"> $(function () { var notifications = $.connection.notificationHub; // 接收服务器推送的最新数据 notifications.client.recieveNotification = function (totalNewMessages) { $('#spanNewMessages').text(totalNewMessages || 0); }; // 定义连接启动逻辑,用于初始化和重连 function startConnection() { $.connection.hub.start() .done(function () { console.log("SignalR连接成功"); // 连接成功后立即请求最新数据 notifications.server.sendNotifications(); }) .fail(function (e) { console.error("连接失败:", e); // 连接失败后5秒重试 setTimeout(startConnection, 5000); }); } // 监听连接断开事件,自动触发重连 $.connection.hub.disconnected(function () { setTimeout(startConnection, 5000); }); // 初始化连接 startConnection(); }); </script> }
4. Startup.cs保持现有配置(无需修改)
[assembly: OwinStartup(typeof(SignalR.Startup))] namespace SignalR { public class Startup { public void Configuration(IAppBuilder app) { app.MapSignalR(); } } }
关键修复点说明
- 持续订阅SqlDependency:每次调用
SendNotifications时创建新的依赖实例,确保数据库变更能持续触发通知 - 数据读取安全:添加
dr.HasRows判断,避免空引用异常 - 内存泄漏防护:触发变更后移除旧的事件绑定,防止资源占用
- 客户端重连机制:连接断开后自动重试,保障实时推送的稳定性
- Service Broker启用:必须在SQL Server中启用该功能,否则SqlDependency无法正常工作
内容的提问来源于stack exchange,提问作者BLAD
相关产品推荐
相关产品推荐

