【问题标题】:SqlDependency OnChange event not firing for SignalRSqlDependency OnChange 事件未针对 SignalR 触发
【发布时间】:2021-01-16 13:32:24
【问题描述】:

我知道关于 SO 的多个问题几乎相同,但不幸的是,在遵循无数指南并阅读了几个答案之后,我无法回答为什么作为 SignalR / SqlDependencies 的新用户会发生这种情况。

我有一个 ASP.Net WebForms 应用程序,它使用 SignalR 将实时图形推送到页面。代码在初始加载时执行,并触发事件,但之后,当依赖项使用OnChange 事件检测到更改时,我无法触发事件。

我可以看到队列和 SP 在服务器上创建得很好,但是当在表中添加/删除或更新数据时,我看不到队列收到任何通知。我认为这可能与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);
    });
});

【问题讨论】:

    标签: asp.net sql-server vb.net signalr sqldependency


    【解决方案1】:

    我不是 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 并让我们知道?

    【讨论】:

    • 感谢您的回复!我已经删除了 Using 容器并保持连接打开,但不幸的是,OnChange 例程仍然没有被放在首位。
    • 感谢更新/编辑!这已经解决了问题并指出了我的问题所在。再次感谢!
    【解决方案2】:

    通知查询有很多限制,详见here。限制之一是:

    该语句不得使用以下任何聚合函数: AVG、COUNT(*)、MAX、MIN、STDEV、STDEVP、VAR 或 VARP。

    如果查询对通知订阅无效,OnChange 处理程序将立即触发 SqlNotificationType.Invalid

    以下是在调用OnChange 时运行类似于您的查询(即使用COUNT 聚合函数)时得到的SqlNotificationEventArgs 属性值:

    Info=Invalid, Source=Statement, Type=Subscribe
    

    但是,您的处理程序代码会静默忽略无效订阅,因为它仅检查 SqlNotificationType.Change

    【讨论】:

    • 感谢您的回复 - 我尝试将查询修改为 SELECT [notification_count] FROM pla.[notif_count] - 我设置的测试表,不幸的是,我得到了相同的行为。该事件最初会触发,但永远不会触发dependency_OnChange 例程。甚至在初始运行时也没有。我可以在服务器上的队列中看到消息,但无论出于何种原因,OnChange 事件都不会触发。
    • @RazorKillBen,The notification is removed after the event fires。您需要使用依赖项再次执行查询才能获得通知。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多