SignalR 向同一用户发送重复消息 n 次 n 是连接的用户数.NetCore

SignalR send duplicate message to same user n times n is number of users connected .NetCore

我有 SignalR ASP.NET 核心项目并尝试向我设法发送消息的特定用户发送消息。问题是相同的消息发送 n 选项卡或连接的时间 n=number 当数据库发生变化时它会向该特定用户发送通知但复制消息。

public class MessageHub: Hub
{       
    public MessageHub(IConfiguration cc, IHubContext<MessageHub> _mess, UserManager<ApplicationUser> rep)
    {
        mess = _mess;
        _conf = cc;
        _usermanager = rep;
        RegisterNotification();
    }

    public void RegisterNotification()
    {        
        using (SqlConnection con = new SqlConnection(conStr))
        {
            SqlCommand cmd = new SqlCommand(sqlCommand, con);

            if (con.State != System.Data.ConnectionState.Open)
            {
                con.Open();
            }

            cmd.Notification = null;
        
            SqlDependency sqlDep = new SqlDependency(cmd);
          
            sqlDep.OnChange += sqlDep_OnChange;
          
            using (SqlDataReader reader = cmd.ExecuteReader())
            {
                // nothing need to add here now
            }
        }
    }

    static int count = 1;
    private  void sqlDep_OnChange(object sender, SqlNotificationEventArgs e)
    {
        if (e.Type == SqlNotificationType.Change )
        {
            SqlDependency sqlDep = sender as SqlDependency;
            sqlDep.OnChange -= sqlDep_OnChange;
                      
            mess.Clients.User("64ed09d7-255f-4aae-a25f-7a50e59943b4").SendAsync("abc", "hello"+count);
            count += 1;

           RegisterNotification();
        }
    }
}

正如您所提到的,问题是每次创建 MessageHub 的实例时都会调用 RegisterNotification。取而代之的是,您可以创建后台服务并在那里注册 SqlDependency,然后使用 IHubContext 发送事件。在每次通知后,您再次调用 RegisterNotification,这也可能导致重复。

我还没有测试过这段代码,但这里有一个例子:

public class EventBroadcaster : IHostedService
{
    private readonly IHubContext<MessageHub> _hubContext;
    private readonly string _connectionString;

    public EventBroadcaster(
           IConfiguration configuration, 
           IHubContext<MessageHub> hubContext)
    {
         _hubContext = hubContext;
         _connectionString = // Get Connection String from configuration
    }

    public Task StartAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("Started event broadcasting service");

        RegisterNotification();
        return Task.CompletedTask;
    }


    public void RegisterNotification()
    {        
        using (SqlConnection con = new SqlConnection(_connectionString))
        {
            SqlCommand cmd = new SqlCommand(sqlCommand, con);

            if (con.State != System.Data.ConnectionState.Open)
            {
                con.Open();
            }

            cmd.Notification = null;
        
            SqlDependency sqlDep = new SqlDependency(cmd);
          
            sqlDep.OnChange += sqlDep_OnChange;
          
            using (SqlDataReader reader = cmd.ExecuteReader())
            {
                // nothing need to add here now
            }
        }
    }

    static int count = 1;
    private async void sqlDep_OnChange(object sender, SqlNotificationEventArgs e)
    {
        if (e.Type == SqlNotificationType.Change )
        {
            SqlDependency sqlDep = sender as SqlDependency;
            sqlDep.OnChange -= sqlDep_OnChange;
                      
            await _hubContext.Clients.User("64ed09d7-255f-4aae-a25f-7a50e59943b4").SendAsync("abc", "hello"+count);

            count += 1;
        }
    }

    public Task StopAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("Event Broadcasting Service is stopping.");

        // TODO: Stop listening to SqlDependency notifications

        return Task.CompletedTask;
    }