SqlDependency具有SignalR

时间:2016-06-13 15:57:41

标签: c# asp.net asp.net-mvc-4 signalr sqldependency

我有一个MVC 4站点,它使用SqlDependency检测数据库的更改,然后通过SignalR通知订阅的客户端更改。所有的机制都已到位,应用程序知道发生了变化,但在这里它变得有趣......我看到越来越多的客户端通知基于{之间发生的浏览器刷新次数{1}}和Application_Start(),或已连接的客户端数量。

也许我的理解是关于这些技术的,但我认为SignalR变成了一个Singleton,它会导致所有流量发生在一个" pipe"客户端和服务器之间,无论连接的客户端数量是多少。

当然,这并不能解释为什么刷新似乎实例化一个全新的SqlDependency。

我看到this answer显示了关闭SqlDependency(模拟Application_End())的想法,但所做的只是在页面上添加执行时间并且没有解决问题。< / p>

我很难过,并且非常感谢一些让我们按预期工作的建议。

这是我正在使用的代码......

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; } } } 注意:我使用Telerik网格,所以我必须在And, finally my .js code for the SignalR:之外进行SignalR连接,这是我在其他所有教程/示例中连接SignalR的地方。

$(document).ready()

1 个答案:

答案 0 :(得分:0)

好的,所以我认为这里有一些事情,你正在添加和删除事件来经常处理sqldependency更改。您应该使用保护逻辑来查看事件处理程序是否存在,删除不存在的处理程序有时会产生奇怪的影响。至于多次启动等,每次重新加载或离开客户端页面时它都会断开连接,并在加载时重新连接。信号器集线器不是单例实例,除非您以这种方式编码,默认情况下不会这样做。这是您想要做的简单版本。

try
    {
        using (
            var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString))
        {
            connection.Open();
            using (SqlCommand command = new SqlCommand(@"SELECT [Id]
                                                                    ,[FName]
                                                                    ,[LName]
                                                                    ,[DOB]
                                                                    ,[Notes]
                                                                    ,[PendingReview] 
                                                   FROM [dbo].[Users]",
                connection))
            {
                // Make sure the command object does not already have
                // a notification object associated with it.
                command.Notification = null;

                SqlDependency dependency = new SqlDependency(command);

                dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);

                if (connection.State == ConnectionState.Closed)
                    connection.Open();

                command.ExecuteReader();
            }
        }
    }
    catch (Exception e)
    {
        throw;
    }
}

private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{   
    SqlDependency dependency = sender as SqlDependency;
    if (dependency != null) dependency.OnChange -= dependency_OnChange;
    //Recall your SQLDependency setup method here.
    SetupDependency();
    JobHub.Show();
}

如果你想创建一个单例类型的集线器,你需要设置一个像这样的东西,你有一个静态集线器和一个集线器跟踪器类,这是在跟踪器类中。查看教程链接以获取更多详细信息:

 private readonly static Lazy<StockTicker> _instance = new Lazy<StockTicker>(() => new StockTicker(GlobalHost.ConnectionManager.GetHubContext<StockTickerHub>().Clients));

 private readonly ConcurrentDictionary<string, Stock> _stocks = new ConcurrentDictionary<string, Stock>();

查看本教程,将集线器用作单例: http://www.asp.net/signalr/overview/getting-started/tutorial-server-broadcast-with-signalr