【问题标题】:SQLDependency with SignalR and MVC. OnChange only firing onceSignalR 和 MVC 的 SQLDependency。 OnChange 只触发一次
【发布时间】:2014-01-19 20:10:12
【问题描述】:

我能够在我的网站仪表板上显示实时行更新。但是,当尝试对通知做几乎完全相同的事情时,我的 onchange 事件只会触发一次。仪表板更新正在使用 SignalR 连接,并且它在 100% 的时间内工作。所有代码实际上都是相同的,除了我每次都在仪表板上获取每一行,并且在获取它们之后没有对数据库进行任何更新。

这就是我想要做的。

  1. 在 dbo.SystemNotifications 中插入一行,标志为 Sent = 0
  2. 订阅更改并使用 jQuery.noty 显示新插入
  3. 将记录更新为已发送 = 1

这在我第一次或任何时候刷新浏览器时都有效,但 SQLDependency onchange 要么在此之后再次触发,要么根本不再触发。

在我的 CUSTOM.JS 文件中

$(document).ready(function ( $ ) {
    var notificationHub = $.connection.notyHub;

    notificationHub.client.showNotification = function () {
        getNotifications();
        markSet();
    };

    $.connection.hub.start();
    getNotifications();

});

function getNotifications() {
    $.ajax({
        url: '../Notification/GetNotifications',
        type: 'GET',
        global: false,
        datatype: 'json',
        success: function (data) {
            if (data.length > 0) {
                for (var i = 0; i < data.length; i++) {
                    noty({
                        text: data[i].NotificationText,
                        type: 'information',
                        timeout: 0,
                        closeWith: ['hover'],
                        maxVisible: 1
                    });

                    markSent(data[i].ID);
                }
            }
        }
    });
}

function markSent(id) {
    $.ajax({                  
        url: '../Notification/MarkNotificationSent',
        type: 'POST',
        data: JSON.stringify({ notyID: id }),
        dataType: 'json',
        contentType: 'application/json',
        global: false,        
        error: function (req, status, error) {
            alert("R: " + req + " S: " + status + " E: " + error);
        }
    });
}

我的控制器

 public class NotificationController : CaseEnhancedController
    {
        private readonly NotificationRepository notyRepo = new NotificationRepository();
        private ReaderWriterLockSlim methodLock = new ReaderWriterLockSlim();

        [OutputCache(Duration = 0)]
        public JsonResult GetNotifications()
        {
            try
            {
                methodLock.EnterWriteLock();

                IEnumerable<Notification> notifications = notyRepo.GetData();
                JsonResult notysJSon = new JsonResult();
                notysJSon.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
                notysJSon.Data = notifications;
                return notysJSon;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (methodLock.IsWriteLockHeld)
                    methodLock.ExitWriteLock();
            }
        }

        [HttpPost]
        public JsonResult MarkNotificationSent(string notyID)
        {
            string sConn = "Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=SirenCMNew;Data Source=localhost";

            try
            {
                methodLock.EnterWriteLock();

                using (SqlConnection connection = new SqlConnection(sConn))
                {
                    if (connection.State == ConnectionState.Closed)
                        connection.Open();

                    using (SqlCommand cmd = new SqlCommand("[dbo].[spMarkNotificationSent]", connection))
                    {
                        cmd.CommandType = CommandType.StoredProcedure;

                        SqlParameter idParm = new SqlParameter
                        {
                            Value = notyID,
                            SqlDbType = SqlDbType.BigInt,
                            ParameterName = "ID"
                        };

                        cmd.Parameters.Add(idParm);
                        cmd.ExecuteNonQuery();
                    }
                }

                return Json(new { result = notyID }, JsonRequestBehavior.AllowGet);
            }
            catch (Exception ex)
            {
                return Json(new { result = 0 }, JsonRequestBehavior.AllowGet);
            }
            finally
            {
                if (methodLock.IsWriteLockHeld)
                    methodLock.ExitWriteLock();
            }
        }  

我的仓库

public class NotificationRepository
{
    string sConn = "Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=SirenCMNew;Data Source=localhost";

    public IEnumerable<Notification> GetData()
    {
        try
        {
            using (var connection = new SqlConnection(sConn))
            {
                connection.Open();
                using (SqlCommand command = new SqlCommand(@"EXEC [dbo].[spGetUnsentNotifications]", connection))
                {
                    command.Notification = null;

                    SqlDependency dependency = new SqlDependency(command);
                    dependency.OnChange += new OnChangeEventHandler(OnChange);

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

                    using (var reader = command.ExecuteReader())
                        return reader.Cast<IDataRecord>()
                            .Select(x => new Notification()
                            {    
                                ID = x.GetInt64(0),
                                NotificationText = x.GetString(1)                                   
                            }).ToList();
                }
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    private void OnChange(object sender, SqlNotificationEventArgs e)
    {
        SqlDependency dependency = sender as SqlDependency;
        dependency.OnChange -= OnChange;

        if (e.Info == SqlNotificationInfo.Insert)
        {
            NotificationHub.Show();
        }
    }

我的集线器

 [HubName("notyHub")]
    public class NotificationHub : Hub
    {
        public static void Show()
        {
            IHubContext context = GlobalHost.ConnectionManager.GetHubContext<JobInfoHub>();            
            context.Clients.All.showNotification();
        }     
    }

存储过程

CREATE PROCEDURE [dbo].[spGetUnsentNotifications]
    AS

    SELECT
        ID, NotificationText
    FROM
        dbo.SystemNotifications
    WHERE
        Sent = 0

GO

CREATE PROCEDURE dbo.spMarkNotificationSent

@ID bigint

AS

UPDATE 
    dbo.SystemNotifications
SET
    Sent = 1
WHERE
    ID = @ID

【问题讨论】:

    标签: jquery asp.net-mvc signalr sqldependency


    【解决方案1】:

    我终于想通了。我不得不采取不同的方法。这是我的做法

    存储库

    if (e.Info == SqlNotificationInfo.Insert)
            {
                id = GetLastRecord();
            }
    
            if (id != 0)
                DeleteNotification(id);
    
            GetData();
        }
    
        private long GetLastRecord()
        {
            Notification notification = null;
            long id = 0;
            try
            {
                using (var connection = new SqlConnection(sConn))
                {
                    connection.Open();
                    using (SqlCommand command = new SqlCommand(@"SELECT TOP 1 ID, NotificationText FROM dbo.SystemNotifications with(nolock)", connection))
                    {
                        if (connection.State == ConnectionState.Closed)
                            connection.Open();
    
                        using (var reader = command.ExecuteReader())
                        {
                            while (reader.Read())
                            {
                                notification = new Notification
                                {
                                    ID = (long)reader.GetSqlInt64(0)
                                    , NotificationText = reader.GetString(1)
                                };
                            }
                        }
    
                        if (null != notification)
                        {
                            NotificationHub.Show(notification);
                            id = notification.ID;
                        }
                        return id;
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    
        private static void DeleteNotification(long notyID)
        {
            string sConn = "Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=SirenCMNew;Data Source=localhost";
    
            try
            {
    
                using (SqlConnection connection = new SqlConnection(sConn))
                {
                    if (connection.State == ConnectionState.Closed)
                        connection.Open();
    
                    using (SqlCommand cmd = new SqlCommand("[dbo].[spDeleteNotification]", connection))
                    {
                        cmd.CommandType = CommandType.StoredProcedure;
    
                        SqlParameter idParm = new SqlParameter
                        {
                            Value = notyID,
                            SqlDbType = SqlDbType.BigInt,
                            ParameterName = "ID"
                        };
    
                        cmd.Parameters.Add(idParm);
                        cmd.ExecuteNonQuery();
                    }
                }
    
            }
            catch (Exception ex)
            {
                //TODO
            }
        }
    

    集线器

    [HubName("notyHub")]
    public class NotificationHub : Hub
    {
        public static void Show(Notification notification)
        {
            IHubContext context = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();
            context.Clients.All.showNoty(notification.ID, notification.NotificationText);
    
        }     
    }
    

    控制器

     public class NotificationController : CaseEnhancedController
    {
        private readonly NotificationRepository notyRepo = new NotificationRepository();
        private ReaderWriterLockSlim methodLock = new ReaderWriterLockSlim();
    
        [OutputCache(Duration = 0)]
        public JsonResult GetNotifications()
        {
            int count = 0;
    
            try
            {
                methodLock.EnterWriteLock();
    
                IEnumerable<Notification> notifications = notyRepo.GetData();
                count = notifications.Count();
                JsonResult notysJSon = new JsonResult();
                notysJSon.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
                notysJSon.Data = notifications;
                return notysJSon;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (methodLock.IsWriteLockHeld)
                    methodLock.ExitWriteLock();
    
                if (count > 0)
                    DeleteNotifications();
            }
        }
    
        private static void DeleteNotifications()
        {
            string sConn = "Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=SirenCMNew;Data Source=localhost";
    
            try
            {
                using (SqlConnection connection = new SqlConnection(sConn))
                {
                    if (connection.State == ConnectionState.Closed)
                        connection.Open();
    
                    using (SqlCommand cmd = new SqlCommand("[dbo].[spDeleteAllNotifications]", connection))
                    {
                        cmd.CommandType = CommandType.StoredProcedure;
                        cmd.ExecuteNonQuery();
                    }
                }
            }
            catch (Exception ex)
            {
                //TODO
            }
        }
    

    JQUERY

    $(function () {
     var notificationHub = $.connection.notyHub;
    
    notificationHub.client.showNoty = function (id, message) {
        showNotification(id, message);
    };
    
    $.connection.hub.start();
    getNotifications();
    }
    
    function showNotification(id, message)
    {
        noty({
            text: message,
            type: 'information',
            timeout: 0,
            closeWith: ['hover'],
            maxVisible: 1
        });
    }
    
    function getNotifications() {
    $.ajax({
        url: '../Notification/GetNotifications',
        type: 'GET',
        global: false,
        datatype: 'json',
        success: function (data) {
            if (data.length > 0) {
                for (var i = 0; i < data.length; i++) {
                    showNotification(data[i].ID, data[i].NotificationText);
                }
            }
        }
    });
    }
    

    【讨论】:

    • 你找到第二次没有触发的原因了吗?我有同样的问题。
    【解决方案2】:

    您应该将您的 sp 写入以下方法:

    CREATE PROCEDURE [dbo].[spGetUnsentNotifications]
    AS
    
    SELECT
        [ID], [NotificationText]
    FROM
        [dbo].[SystemNotifications]
    WHERE
        [Sent] = 0
    
    GO
    
    CREATE PROCEDURE [dbo].[spMarkNotificationSent]
    
    @ID bigint
    
    AS
    
    UPDATE 
    [dbo].[SystemNotifications]
    SET [Sent] = 1 
    WHERE [ID] = @ID
    

    【讨论】:

      猜你喜欢
      • 2021-01-16
      • 1970-01-01
      • 1970-01-01
      • 2018-01-09
      • 1970-01-01
      • 1970-01-01
      • 2023-04-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多