【发布时间】:2016-06-13 15:57:40
【问题描述】:
我有一个 MVC 4 站点,它使用 SqlDependency 来检测对数据库的更改,然后通过 SignalR 通知订阅的客户端更改。所有机制都已到位,应用程序知道发生的变化,但有趣的是……我看到越来越多的客户端通知基于在 Application_Start() 和 @ 之间发生的任一浏览器刷新次数987654324@,或者连接的客户端数量。
也许我对这些技术的理解不正确,但我认为 SignalR 变成了单例,这导致所有流量都通过客户端和服务器之间的单个“管道”发生,而不管连接的客户端数量如何.
当然,这并不能解释为什么刷新似乎会实例化一个全新的 SqlDependency。
我看到 this answer 显示了关闭 SqlDependency 的想法(模拟 Application_End()),但所做的只是增加了页面的执行时间,并没有解决问题。
我很难过,非常感谢一些建议,以使其按预期工作。
这是我正在使用的代码...
In my Global.asax.cs file:
using System.Configuration;
using System.Data.SqlClient;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
namespace SmartAppV1
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
// SignalR Wireup
SqlDependency.Start(ConfigurationManager.ConnectionStrings["SmartAppSignalR"].ConnectionString);
}
protected void Application_End()
{
// Shut down SignalR Dependencies
SqlDependency.Stop(ConfigurationManager.ConnectionStrings["SmartAppSignalR"].ConnectionString);
}
}
}
My SignalR Hub:
using System.Collections.Generic;
using System.Configuration;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
using SmartAppData.Entities;
using SmartAppV1.Models;
namespace SmartAppV1
{
[HubName("smartAppHub")]
public class SmartAppHub : Hub
{
private readonly string _connection = ConfigurationManager.ConnectionStrings["SmartAppSignalR"].ConnectionString;
public void MonitorGrid4DataChanges()
{
var setGrid4 = new SmartAppSignalR
{
ConnectionString = _connection,
Query =
@"SELECT [ID], [OrdHeaderId], [LoadId], [NewStatus] FROM [dbo].[CTLoadStatusChangeLog] WHERE [NewStatus] = 'Delivered' ORDER BY [ID] DESC"
};
setGrid4.DispatchBoardStatusChange();
}
}
}
My SignalR class:
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using Microsoft.AspNet.SignalR;
using SmartAppData;
using SmartAppData.Entities;
using SmartAppData.Services;
namespace SmartAppV1.Models
{
public class SmartAppSignalR
{
public string ConnectionString { get; set; }
public string Query { get; set; }
public IEnumerable<DeliveredGridItem> ReadGrid4Data()
{
var service = new LoadService();
var result = service.GetLoadsByBookedByIdByTmsStatus(110, LoadTmsStatus.Delivered.ToString()).ToList();
var deliveredList = new List<DeliveredGridItem>();
foreach (var obj in result)
{
var deliveredItem = new DeliveredGridItem(obj.LoadId) { LoadTmsStatus = obj.DataValue_LoadTmsStatus };
deliveredList.Add(deliveredItem);
}
return deliveredList;
}
public void DispatchBoardStatusChange()
{
using (var conn = new SqlConnection(ConnectionString))
{
using (var cmd = new SqlCommand(Query, conn))
{
cmd.Notification = null;
var dependency = new SqlDependency(cmd);
// make sure the OnChange doesn't exist
// trying to remove redundant calls
dependency.OnChange -= dispatchBoard_OnChange;
dependency.OnChange += dispatchBoard_OnChange;
if (conn.State == ConnectionState.Closed)
conn.Open();
var reader = cmd.ExecuteReader();
while (reader.Read())
{
}
}
}
}
private void dispatchBoard_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type != SqlNotificationType.Change) return;
// dump the original OnChange event handler...we're going to re-register it
var sqlDependency = (SqlDependency) sender;
sqlDependency.OnChange -= dispatchBoard_OnChange;
var retVal = new StatusChangedObject();
using (var conn = new SqlConnection(ConnectionString))
{
using (var cmd = new SqlCommand(Query, conn))
{
if (conn.State == ConnectionState.Closed)
conn.Open();
var reader = cmd.ExecuteReader();
if (reader.Read())
{
retVal.Id = Convert.ToInt32(reader["ID"]);
retVal.OrdHeaderId = Convert.ToInt32(reader["OrdHeaderId"]);
retVal.LoadId = Convert.ToInt32(reader["LoadId"]);
retVal.NewStatus = reader["NewStatus"].ToString();
var clients = GlobalHost.ConnectionManager.GetHubContext<SmartAppHub>().Clients;
clients.All.gridUpdate(retVal);
}
}
}
// Re-register the SqlDependency
DispatchBoardStatusChange();
}
}
public class StatusChangedObject
{
public int Id { get; set; }
public int OrdHeaderId { get; set; }
public int LoadId { get; set; }
public string NewStatus { get; set; }
}
}
And, finally my .js code for the SignalR:
注意:我使用的是 Telerik 网格,因此我必须在 $(document).ready() 之外使用 SignalR 接线,这是我看到的所有其他教程/连接 SignalR 示例的地方。
// SignalR plumbing
var hub, hubStart;
hub = $.connection.smartAppHub;
hubStart = $.connection.hub.start().done(function () {
if ($.connection.hub.state === $.signalR.connectionState.connected) {
console.log('SignalR is connected.');
console.log('Call the server method to monitor changes to Grid4');
hub.server.monitorGrid4DataChanges();
};
});
hub.client.grid4Read = function () {
console.log('Called grid4Read()');
};
hub.client.iDidSomething = function (response) {
console.log('I was told to do something\r\n' + response);
};
hub.client.gridUpdate = function (response) {
console.log("Entered hub.client.gridUpdate");
// Will show alerts when something moves.
// Plan on adjusting this via the 'Settings' menu.
var showNotification = true;
// Go get the order/load from the database
var ordHeaderId = response['OrdHeaderId'];
var loadId = response['LoadId'];
var newStatus = response['NewStatus'];
if (showNotification) {
//setToastrOptions();
//toastr["info"]("Grid update to loadId: " + loadId);
}
console.log('Client-side fromSqlDependency:\r\nOrdHeaderId: ' + ordHeaderId + '\r\nLoadId: ' + loadId + '\r\nNewStatus: ' + newStatus);
};
【问题讨论】:
-
你可以点击这个链接,它可能会解决你的问题。stackoverflow.com/questions/21448204/…
标签: c# asp.net asp.net-mvc-4 signalr sqldependency