使用SignalR和MVC的SQLDependency。 OnChange只发射一次

时间:2014-01-19 20:10:12

标签: jquery asp.net-mvc signalr sqldependency

我可以在我的网站信息中心上显示实时行更新。但是,当尝试使用通知几乎完全相同时,我的onchange事件只会触发一次。 Signalboard连接正由仪表板更新使用,它可以100%的时间工作。所有代码几乎完全相同,除了我每次都在仪表板上获取每一行,并且在获取数据库后不对数据库进行任何更新。

这就是我想要做的事情。

  1. 在dbo.SystemNotifications中插入一行,标志为Sent = 0
  2. 使用jQuery.noty订阅更改并显示新插入
  3. 将记录更新为sent = 1
  4. 这是我第一次或任何时候刷新浏览器,但SQLDependency onchange在此之后再次触发或者根本不再触发。

    IN MY CUSTOM.JS FILE

    $(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();
                }
            }  
    

    MY REPOSITORY

    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();
            }
        }
    

    MY HUB

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

    THE SPROCS

    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
    

2 个答案:

答案 0 :(得分:0)

我终于弄明白了。我不得不采取不同的方法。这就是我做的方式

THE REPOSITORY

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
        }
    }

THE HUB

[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
        }
    }

THE 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);
            }
        }
    }
});
}

答案 1 :(得分:0)

您应该将以下方法编写为&#39; e 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