首页 > 解决方案 > Asp.Net Core 3.1 Web App(Razor Pages)SignalR - OnChange 事件在 SqlDependency 上多次命中,对于单个客户端

问题描述

我有一个聊天功能,可以在从数据库到客户端的触发更改方面起作用。但是,当超过 1 个客户端连接并推送更改后,似乎为每个已连接的客户端递归调用 SQlDependency OnChange,导致返回的响应溢出返回到触发 SqlDependency 上的 OnChange 事件的所有客户端。

我已经梳理了这个类似的线程: **SignalR** SQLDependency Onchanged 多次触发

但是这个线程是基于一个 Asp.Net MVC 项目,它更多地关注 Hub 类;我什至不必接触 Hub 类。

这是我用作指南的项目,但这也有相同的错误/问题: https ://github.com/upretymadan45/database-change-notification-using-signal-r

我的仓库:

public class NewCaseInternalCommentsRepository : INewCaseInternalCommentsRepository
{
    private readonly IHubContext<MySigServer> _context;

    string connectionString = "";

    public string newCaseId { get; set; }

    public NewCaseInternalCommentsRepository(IConfiguration configuration,
                                IHubContext<MySigServer> context)
    {
        connectionString = configuration.GetConnectionString("SigRConnection");
        _context = context;
    }

    public List<NewCaseInternalComments> GetAllThisNewCaseInternalComments()
    {

        var comments = new List<NewCaseInternalComments>();

        using (SqlConnection conn = new SqlConnection(connectionString))
        {
            conn.Open();

            SqlDependency.Start(connectionString);

            string commandText = "SELECT id, NewCaseId, TimeStamp, UserId, UserName, UserComment FROM dbo.NewCaseInternalComments WHERE NewCaseId = '" + newCaseId + "'";

            SqlCommand cmd = new SqlCommand(commandText, conn);

            SqlDependency dependency = new SqlDependency(cmd);

            dependency.OnChange += new OnChangeEventHandler(dbChangeNotification);

            var reader = cmd.ExecuteReader();

            while (reader.Read())
            {
                var newCaseInternalComments = new NewCaseInternalComments
                {
                    id = Convert.ToInt32(reader["id"]),
                    TimeStamp = DateTime.Parse(reader["TimeStamp"].ToString()),
                    UserId = reader["UserId"].ToString(),
                    UserName = reader["UserName"].ToString(),
                    UserComment = reader["UserComment"].ToString()
                };

                comments.Add(newCaseInternalComments);
            }
        }

        return comments;
    }


    private void dbChangeNotification(object sender, SqlNotificationEventArgs e)
    {          
        _context.Clients.All.SendAsync("refreshInternalComments");
    }

}

中心:

public class MySigServer : Hub {   
    
    
}

页面控制器:

public IActionResult OnPostRetreiveInternalComments([FromBody] NewCaseInternalComments obj)
{

     _repository.newCaseId = obj.NewCaseId.ToString();

     return new JsonResult(_repository.GetAllThisNewCaseInternalComments());
}

在 Page 控制器中,我调用了 repo 的接口:

public interface INewCaseInternalCommentsRepository
    {
        List<NewCaseInternalComments> GetAllThisNewCaseInternalComments();

        string newCaseId { get; set; }
    }

在启动文件中,我为 INewCaseInternalCommentsRepository 接口尝试了 AddSingleton 和 AddTransient ,但都没有运气:

services.AddTransient<INewCaseInternalCommentsRepository, NewCaseInternalCommentsRepository>();

JavaScript:

function OpenInternalCommentsPipe(ncID) {

    if (connection.connectionState != "Connected") {
        connection.start();
    }

    connection.on("refreshInternalComments", function () {
        loadData();
    });

    loadData();

    function loadData() {

        console.log("Hello! Something was changed!!!!");
        console.log(ncID);

        $.ajax({
            url: '/Identity/Account/Manage/ManagePPS?handler=RetreiveInternalComments',
            type: "POST",

            beforeSend: function (xhr) {
                xhr.setRequestHeader("XSRF-TOKEN",
                    $('input:hidden[name="__RequestVerificationToken"]').val());
            },

            data: JSON.stringify({
                NewCaseId: ncID
            }),
            contentType: "application/json; charset=utf-8",
            dataType: "json",

            success: function (data, response) {
                PaintInternalCommentsFromTunnel(data);                
            },

            error: (jqXHR, error) => {
                console.log("Something went wrong!");
                console.log(jqXHR)
                console.log(error)
            }
        });
    }
}

唯一要提到的另一件事是 SignalR 脚本在一个函数 (OpenInternalCommentsPipe()) 中被调用,该函数在 DevExtreme Popup 的 OnShowing() 方法中触发。我在全局变量中初始化 SingnalR js 对象:

const connection = new signalR.HubConnectionBuilder().withUrl("/mySigServer").build();

并在同一个 DevExtreme Popup 的 OnHiding() 中关闭连接:

connection.stop();

每当桌子上发生变化时,我希望它只为每个客户返回一次。

任何帮助将非常感激!

标签: asp.net-coresignalrasp.net-core-signalrsignalrcore

解决方案


推荐阅读