ASP.NET Core中如何在多个cshtml文件复用SignalR连接
ASP.NET Core中复用SignalR连接的解决方案
问题场景
在ASP.NET Core项目的_Layout.cshtml脚本块中创建并启动了SignalR连接,IndexNew.cshtml引用该布局页,希望复用_Layout中已创建的连接以避免重复实例化。曾尝试将连接代码抽成独立JS文件,但导入到两个页面仍会创建两个连接,需解决连接复用问题。
解决步骤
1. 将连接实例暴露到全局作用域
原代码中const connection是$(document).ready内部的局部变量,子页面无法访问。需将其挂载到window全局对象,让所有引用该布局的页面都能获取到同一个实例。
修改后的_Layout.cshtml脚本部分:
<script> $(document).ready(function () { setInterval(makeAjaxCall, 600000) // 将连接挂载到window全局对象,确保子页面可访问 window.auctionHubConnection = new signalR.HubConnectionBuilder() .withUrl("/auctionHub") .build(); window.auctionHubConnection.start().then(function () { console.log("Bağlantı başlatıldı."); }).catch(function (err) { console.error(err); }); window.auctionHubConnection.on("connected", function () { console.log("Bağlandı"); }); window.auctionHubConnection.on("ReceiveBidLayout", function (acutionId, propertyCode) { $("#auctionId").text(acutionId); $("#propertyCode").text(propertyCode); }); }); </script>
2. 子页面复用全局连接并注册事件
子页面IndexNew.cshtml直接使用全局的连接实例,同时需处理连接可能未完成初始化的情况,确保事件注册在连接启动后执行。
修改后的IndexNew.cshtml脚本部分:
<script> var input = document.getElementById("inputNumber"); var button = document.getElementById("buttonNumber"); var validate_error = document.querySelector(".validate"); var maxBid = 0; $(document).ready(function () { // 复用全局连接实例 if (window.auctionHubConnection) { // 根据连接状态决定何时注册事件 if (window.auctionHubConnection.state === signalR.HubConnectionState.Connected) { registerHubEvents(); } else { // 若连接未启动,等待启动完成后注册事件 window.auctionHubConnection.start() .then(registerHubEvents) .catch(err => console.error(err)); } } function registerHubEvents() { window.auctionHubConnection.on("connected", function () { console.log("Bağlandı"); }); // 修正原代码的语法错误:括号位置错误 window.auctionHubConnection.on("addAuctionMember", function (count) { $("#lblTotalMember").text(count); }); window.auctionHubConnection.on("ReceiveBid", function (result) { $("#lblTotalMember").text(result.totalMember); $("#labelTotalBid").text(result.totalBidAmount); $("#lblMaxBid").text(result.lastBid); document.getElementById("hMaxBid").innerHTML = result.lastBid; maxBid = result.lastBid; }); } }); </script>
3. 可选优化:封装为单例模块(更规范的写法)
如果项目中有多个页面需要复用连接,可将连接逻辑封装成单例模块,确保全局仅创建一次连接:
新建auctionHub.js文件:
(function(window) { let connectionInstance; function getAuctionHubConnection() { if (!connectionInstance) { connectionInstance = new signalR.HubConnectionBuilder() .withUrl("/auctionHub") .build(); connectionInstance.start().then(() => { console.log("Bağlantı başlatıldı."); }).catch(err => console.error(err)); // 布局页需要的事件监听可放在这里 connectionInstance.on("connected", () => { console.log("Bağlandı"); }); connectionInstance.on("ReceiveBidLayout", (acutionId, propertyCode) => { $("#auctionId").text(acutionId); $("#propertyCode").text(propertyCode); }); } return connectionInstance; } window.AuctionHub = { getConnection: getAuctionHubConnection }; })(window);
在_Layout.cshtml中引入该JS文件:
<script src="~/js/auctionHub.js"></script>
子页面IndexNew.cshtml中使用:
$(document).ready(function () { const connection = window.AuctionHub.getConnection(); // 注册子页面专属事件 connection.on("ReceiveBid", function (result) { // 事件逻辑 }); });
注意事项
- 避免使用过于通用的全局变量名(如
connection),建议用独特命名(如auctionHubConnection)防止命名冲突 - 子页面需处理连接未初始化的边界情况,避免控制台报错
- 注意修正原代码中的语法错误(如
addAuctionMember事件的括号位置错误)
内容的提问来源于stack exchange,提问作者Onur Serbes
相关产品推荐
相关产品推荐

