为什么SignalR改变功能多次击中?

时间:2016-06-15 13:18:33

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

我尝试开发一个asp.net mvc应用程序,并尝试使用signalr。问题是我有两个表来控制项目中的用户通知。我有一个Notification表和NotificationUser表,它是多对多的通知和用户表。我正在尝试,如果用户在系统中向另一个用户创建通知,我会尝试显示一个弹出窗口,用一个简单的消息来确认用户,例如'嘿!收到新通知'。问题是信号器的javascript更改功能击中了这么多次。我在下面列出的signalR中使用的所有步骤

存储过程

    ALTER PROCEDURE [dbo].[GetNotifications]

    @userid int
    AS
    BEGIN
    select n.Ntf_Title,Ntf_Description,n.Ntf_Date from dbo.SysNotifications n INNER JOIN dbo.SysNotificationUser u on  n.Ntf_ID =u.NtU_NtfID where    NtU_UserID=@userid AND NtU_IsRead=0
    END

The Hub

 [HubName("signalRHub")]
 public class NtfHub : Hub
 {
    [HubMethodName("notifyChanges")]
    public static void NotifyChanges()
    {
        var context = GlobalHost.ConnectionManager.GetHubContext<NtfHub>();
        context.Clients.All.notifyChanges();
    }


}

StartUp Class

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.MapSignalR();

    }
}

部分视图

 [HttpGet]
    public ActionResult GetNtf()
    {

        //NtfRepo rp = new NtfRepo(this.HttpContext);
        string connectionString = ConfigurationManager.ConnectionStrings["conn"].ConnectionString;
        int userid =id;
        using (SqlConnection sqlcon = new SqlConnection(connectionString))
        {
            using (SqlCommand sqlcom = new SqlCommand("[GetNotifications]", sqlcon))
            {
                sqlcon.Open();
                sqlcom.CommandType = CommandType.StoredProcedure;
                sqlcom.Parameters.AddWithValue("@userid", userid);
                sqlcom.Notification = null;
                SqlDependency dependancy = new SqlDependency(sqlcom);
                dependancy.OnChange += dependancy_OnChange;
                var reader = sqlcom.ExecuteReader();
                var ntf= reader.Cast<IDataRecord>()
                   .Select(e => new PopulateNtfBar()
                   {
                       Title = e.GetString(0),
                       Description = e.GetString(1),
                       TimeDiff = FindDifferenceTime(e.GetDateTime(2))
                   }).ToList();
                return PartialView("~/Views/Shared/CheckNotification.cshtml", ntf);
            }
        }
    }

最后,剧本

  $(function () {
        var notification = $.connection.signalRHub;

        // Create a function that the hub can call to broadcast messages.
        notification.client.notifyChanges = function () {
            getData();
            toastr.warning("Hey,You have Ntf");
        };

        // Start the connection.
        $.connection.hub.start().done(function () {
            getData();
        }).fail(function (e) {
        });
    });


    function getData() {
        var tbl = $("#header_notification_bar")
        $.ajax({
            url: '@Url.Action("GetNtf","Home")',
            contentType: 'application/html ; charset:utf-8',
            type: 'GET',
            dataType: 'html'
        }).success(function (result) {
            tbl.empty().append(result);

        }).error(function () {

        });


    }
如果用户创建通知,

notification.client.notifyChanges会多次击中。问题出在哪里?任何的想法?我无法优化它

编辑1 我在控制器中调用NtfHub.NotifyChanges。

  void dependancy_OnChange(object sender, SqlNotificationEventArgs e)
    {
        if (e.Type == SqlNotificationType.Change)
        {
            NtfHub.NotifyChanges();
        }
    }

2 个答案:

答案 0 :(得分:0)

虽然我认为SqlDependency对于此功能是错误的方法,但您可以尝试以这种方式解决此特定问题:
将参数“subscribeToNotifications”添加到控制器操作

public ActionResult GetNtf(bool subscribeToNotifications)

仅当它为True时才创建SqlDependency 然后在hub启动时订阅 only 上的通知(这将阻止为同一用户创建多个SqlDependencies):

$(function () {
    var notification = $.connection.signalRHub;

    // Create a function that the hub can call to broadcast messages.
    notification.client.notifyChanges = function () {
        getData(false);
        toastr.warning("Hey,You have Ntf");
    };

    // Start the connection.
    $.connection.hub.start().done(function () {
        getData(true);
    }).fail(function (e) {
    });
});


function getData(subscribeToNotifications) {
    var tbl = $("#header_notification_bar")
    $.ajax({
        url: '@Url.Action("GetNtf","Home")' + '?subscribeToNotifications=' + subscribeToNotifications,
        contentType: 'application/html ; charset:utf-8',
        type: 'GET',
        dataType: 'html'
    }).success(function (result) {
        tbl.empty().append(result);

    }).error(function () {

    });
}

但请注意,每次页面刷新仍会创建新的侦听器,而无需管理服务器端的订阅。

选项2 是创建单个SqlDependency(在服务器应用启动时)省略userId参数 - 无论如何,无论哪个用户收到消息,您都会向所有用户发送通知。

选项3 - 真正的解决方案是完全摆脱SqlDependency并向特定用户(消息的收件人)发送通知

答案 1 :(得分:0)

原因是你没有取消订阅dependancy_OnChange事件,sqldependency触发器是一次性执行,所以你必须在每次触发时订阅新的,你不做的是取消订阅前一个事件处理程序,因此当您订阅新的处理程序时,您现在有多个处理程序用于同一个触发器。

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