SqlDependency OnChange 事件未针对 SignalR 触发
SqlDependency OnChange event not firing for SignalR
我知道有多个关于 SO 的问题几乎相同,但不幸的是,在遵循了无数指南并阅读了几个答案之后,我无法回答为什么作为 SignalR 的新用户会出现这种情况 / SqlDependencies.
我有一个 ASP.Net WebForms 应用程序,它使用 SignalR 将实时图形推送到页面。代码在初始加载时执行,并触发事件,但之后,当依赖项使用 OnChange
事件检测到更改时,我无法触发事件。
我可以看到队列和 SP 在服务器上创建得很好,但是当数据 added/removed 或在 table 中更新时,我看不到队列收到任何通知.我认为这可能与 OnChange
重新订阅有关,但我不完全确定。
什么可能导致事件在初始加载后未触发或未收到来自 SQL 的通知?
我已经在下面发布了所有代码:
集线器代码
Namespace SignalR.Models
<HubName("notificationHub")>
Public Class NotificationHub
Inherits Hub
Private notifCount As Integer
<HubMethodName("sendNotifications")>
Public Sub SendNotifications()
Using db As SqlConnection = New SqlConnection(System.Web.Configuration.WebConfigurationManager.ConnectionStrings("aspCreate_fetch2").ConnectionString)
Dim query As String = " SELECT IIF(COUNT(l.[id]) > 99, 99, COUNT(l.[id]))
FROM pla.[lv_test] as l
WHERE 1=1
AND l.[lv_int_id] = 419"
Using sp As SqlCommand = New SqlCommand(query, db)
Dim dependency As SqlDependency = New SqlDependency(sp)
AddHandler dependency.OnChange, New OnChangeEventHandler(AddressOf dependency_OnChange)
sp.Notification = Nothing
Dim dt As DataTable = New DataTable()
db.Open()
If db.State = ConnectionState.Closed Then db.Open()
Dim reader = sp.ExecuteReader()
dt.Load(reader)
If dt.Rows.Count > 0 Then
notifCount = Int32.Parse(dt.Rows(0)(0).ToString())
End If
Dim context = GlobalHost.ConnectionManager.GetHubContext(Of NotificationHub)()
context.Clients.All.ReceiveNotification(notifCount)
End Using
End Using
End Sub
Private Sub dependency_OnChange(sender As Object, e As SqlNotificationEventArgs)
If e.Type = SqlNotificationType.Change Then
SendNotifications()
End If
End Sub
End Class
End Namespace
全球 ASAX
Sub Application_Start(sender As Object, e As EventArgs)
Dim sConn = System.Web.Configuration.WebConfigurationManager.ConnectionStrings("redacted1").ConnectionString
' Fires when the application is started
RouteConfig.RegisterRoutes(RouteTable.Routes)
BundleConfig.RegisterBundles(BundleTable.Bundles)
SqlDependency.[Stop](sConn)
SqlDependency.Start(sConn)
End Sub
Private Sub Application_End(ByVal sender As Object, ByVal e As EventArgs)
Dim sConn = System.Web.Configuration.WebConfigurationManager.ConnectionStrings("redacted1").ConnectionString
SqlDependency.[Stop](sConn)
End Sub
JavaScript
$(function () {
var nf = $.connection.notificationHub;
nf.client.receiveNotification = function (notifCount) {
console.log("connection started");
$("#notif-badge").text(notifCount);
}
$.connection.hub.start().done(function () {
nf.server.sendNotifications();
}).fail(function (e) {
alert(e);
});
});
我不是 VB 或 Javascript 专家,但我相信您对 OnChange 的订阅在退出 SendNotifications() 后立即被删除。
在您的代码中,您具有以下依赖项:
SqlDependency -> SqlCommand -> SqlConnection
并且您正在附加到 SqlDependency 对象。但是,因为您的 SqlConnection 是在方法的末尾处理的,所以您的订阅就没有了。
将您的 SqlConnection 声明为私有 属性 并保持连接打开。此外,将事件订阅移动到单独的初始化方法或构造函数中仅执行一次。
编辑 :
这里大致是我的想法(在 C# 中,对不起 ^^ ):
public class DemoSqlSubscriber : Hub
{
readonly string connectionString = System.Web.Configuration.WebConfigurationManager.ConnectionStrings("aspCreate_fetch2").ConnectionString;
private SqlDependency dependency;
public void StartListening()
{
SqlDependency.Start(connectionString);
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();
SqlCommand command=new SqlCommand();
command.CommandText= "SELECT [notification_count] FROM pla.[notif_count]";
command.Connection = connection;
command.CommandType = CommandType.Text;
dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(OnCountChanged);
}
private void OnCountChanged(object s,SqlNotificationEventArgs e)
{
if(e.Type == SqlNotificationType.Change)
{
// Publish
IHubContext<NotificationHub> context = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();
context.Clients.All.ReceiveNotification(notifCount);
}
}
public void StopListening()
{
SqlDependency.Stop(connectionString);
}
}
您能否尝试在 VB 中相应地构建您的 Hub。 NET 让我们知道?
通知查询有很多限制,详见here。限制之一是:
The statement must not use any of the following aggregate functions:
AVG, COUNT(*), MAX, MIN, STDEV, STDEVP, VAR, or VARP.
如果查询对于通知订阅无效,OnChange
处理程序将立即触发 SqlNotificationType.Invalid
。
下面是 SqlNotificationEventArgs
属性 我得到的值 运行 一个类似于你的查询(即使用 COUNT
聚合函数) OnChange
被调用:
Info=Invalid, Source=Statement, Type=Subscribe
但是,您的处理程序代码会默默地忽略无效订阅,因为它只检查 SqlNotificationType.Change
。
我知道有多个关于 SO 的问题几乎相同,但不幸的是,在遵循了无数指南并阅读了几个答案之后,我无法回答为什么作为 SignalR 的新用户会出现这种情况 / SqlDependencies.
我有一个 ASP.Net WebForms 应用程序,它使用 SignalR 将实时图形推送到页面。代码在初始加载时执行,并触发事件,但之后,当依赖项使用 OnChange
事件检测到更改时,我无法触发事件。
我可以看到队列和 SP 在服务器上创建得很好,但是当数据 added/removed 或在 table 中更新时,我看不到队列收到任何通知.我认为这可能与 OnChange
重新订阅有关,但我不完全确定。
什么可能导致事件在初始加载后未触发或未收到来自 SQL 的通知?
我已经在下面发布了所有代码:
集线器代码
Namespace SignalR.Models
<HubName("notificationHub")>
Public Class NotificationHub
Inherits Hub
Private notifCount As Integer
<HubMethodName("sendNotifications")>
Public Sub SendNotifications()
Using db As SqlConnection = New SqlConnection(System.Web.Configuration.WebConfigurationManager.ConnectionStrings("aspCreate_fetch2").ConnectionString)
Dim query As String = " SELECT IIF(COUNT(l.[id]) > 99, 99, COUNT(l.[id]))
FROM pla.[lv_test] as l
WHERE 1=1
AND l.[lv_int_id] = 419"
Using sp As SqlCommand = New SqlCommand(query, db)
Dim dependency As SqlDependency = New SqlDependency(sp)
AddHandler dependency.OnChange, New OnChangeEventHandler(AddressOf dependency_OnChange)
sp.Notification = Nothing
Dim dt As DataTable = New DataTable()
db.Open()
If db.State = ConnectionState.Closed Then db.Open()
Dim reader = sp.ExecuteReader()
dt.Load(reader)
If dt.Rows.Count > 0 Then
notifCount = Int32.Parse(dt.Rows(0)(0).ToString())
End If
Dim context = GlobalHost.ConnectionManager.GetHubContext(Of NotificationHub)()
context.Clients.All.ReceiveNotification(notifCount)
End Using
End Using
End Sub
Private Sub dependency_OnChange(sender As Object, e As SqlNotificationEventArgs)
If e.Type = SqlNotificationType.Change Then
SendNotifications()
End If
End Sub
End Class
End Namespace
全球 ASAX
Sub Application_Start(sender As Object, e As EventArgs)
Dim sConn = System.Web.Configuration.WebConfigurationManager.ConnectionStrings("redacted1").ConnectionString
' Fires when the application is started
RouteConfig.RegisterRoutes(RouteTable.Routes)
BundleConfig.RegisterBundles(BundleTable.Bundles)
SqlDependency.[Stop](sConn)
SqlDependency.Start(sConn)
End Sub
Private Sub Application_End(ByVal sender As Object, ByVal e As EventArgs)
Dim sConn = System.Web.Configuration.WebConfigurationManager.ConnectionStrings("redacted1").ConnectionString
SqlDependency.[Stop](sConn)
End Sub
JavaScript
$(function () {
var nf = $.connection.notificationHub;
nf.client.receiveNotification = function (notifCount) {
console.log("connection started");
$("#notif-badge").text(notifCount);
}
$.connection.hub.start().done(function () {
nf.server.sendNotifications();
}).fail(function (e) {
alert(e);
});
});
我不是 VB 或 Javascript 专家,但我相信您对 OnChange 的订阅在退出 SendNotifications() 后立即被删除。
在您的代码中,您具有以下依赖项:
SqlDependency -> SqlCommand -> SqlConnection
并且您正在附加到 SqlDependency 对象。但是,因为您的 SqlConnection 是在方法的末尾处理的,所以您的订阅就没有了。
将您的 SqlConnection 声明为私有 属性 并保持连接打开。此外,将事件订阅移动到单独的初始化方法或构造函数中仅执行一次。
编辑 :
这里大致是我的想法(在 C# 中,对不起 ^^ ):
public class DemoSqlSubscriber : Hub
{
readonly string connectionString = System.Web.Configuration.WebConfigurationManager.ConnectionStrings("aspCreate_fetch2").ConnectionString;
private SqlDependency dependency;
public void StartListening()
{
SqlDependency.Start(connectionString);
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();
SqlCommand command=new SqlCommand();
command.CommandText= "SELECT [notification_count] FROM pla.[notif_count]";
command.Connection = connection;
command.CommandType = CommandType.Text;
dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(OnCountChanged);
}
private void OnCountChanged(object s,SqlNotificationEventArgs e)
{
if(e.Type == SqlNotificationType.Change)
{
// Publish
IHubContext<NotificationHub> context = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();
context.Clients.All.ReceiveNotification(notifCount);
}
}
public void StopListening()
{
SqlDependency.Stop(connectionString);
}
}
您能否尝试在 VB 中相应地构建您的 Hub。 NET 让我们知道?
通知查询有很多限制,详见here。限制之一是:
The statement must not use any of the following aggregate functions: AVG, COUNT(*), MAX, MIN, STDEV, STDEVP, VAR, or VARP.
如果查询对于通知订阅无效,OnChange
处理程序将立即触发 SqlNotificationType.Invalid
。
下面是 SqlNotificationEventArgs
属性 我得到的值 运行 一个类似于你的查询(即使用 COUNT
聚合函数) OnChange
被调用:
Info=Invalid, Source=Statement, Type=Subscribe
但是,您的处理程序代码会默默地忽略无效订阅,因为它只检查 SqlNotificationType.Change
。