我开发了一个网页,该网页连接到signalR集线器,并使用angularjs挂接到jQuery代码中。发生sqldependency.onchange事件时,会向客户端发送一条消息,但是,对于连接的每个客户端,该消息都会重复发送给每个客户端。因此,如果连接了两个客户端,则每个客户端都会收到两条消息,依此类推。

步骤如下:

  • 将两个客户端连接到集线器
  • 使数据库更改
  • sqlDependency.onchange触发
  • 调用中心函数clients.all.renewProducts()
  • 重新创建数据存储库重置依赖项
  • 客户端控制台:"Database SQL Dependency change detected: Update" app.js:44:12 (Twice)

  • Hub.cs
    public static void SignalRGetData(string data)
    {
          IHubContext context = GlobalHost.ConnectionManager.GetHubContext<SignalRGetData>();
          context.Clients.All.renewData(data);
    
          // Recereate data and sql dependency
          new DataRespository().GetData();
    }
    

    DataRespository.cs
    _dependency_On更改
    public void _dependency_OnChange(object sender, SqlNotificationEventArgs e)
    {
        if(e.Info == SqlNotificationInfo.Update)
        {
            ProductHub.GetProducts("Database SQL Dependency change detected: " + e.Info);
        }
    

    }

    GetData
    public IEnumerable<ProductInventoryDetail> GetData()
    {
         using(var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["DynamicPricing"].ConnectionString))
         {
              conn.Open();
              var reposQuery =
              "SELECT [ID], [Program] FROM [DBO].[Detail]";
              using(SqlCommand cmd =  new SqlCommand(reposQuery, conn))
              {
                    // remove any command object notifications
                    cmd.Notification = null;
                    // create dependency
                    SqlDependency dependency = new SqlDependency(cmd);
                    dependency.OnChange += new OnChangeEventHandler(_dependency_OnChange);
    
                    if (conn.State == System.Data.ConnectionState.Closed)
                        conn.Open();
    
                    // Execute Sql Command
                    using(var reader = cmd.ExecuteReader())
                    {
                        return reader.Cast<IDataRecord>().Select(x => new ProductInventoryDetail(){
    
                             ID = x.GetInt32(0),
                             Program = x.GetInt32(1)
                         }
                     }
               }
          }
    }
    

    Angular JavaScript
    // Apply jQuery SignalR operations to Angular
    app.value('$', $);
    
    app.factory('signalRService', ['$', '$rootScope', function ($, $rootScope) {
    
        var proxy = null;
        var initialise = function () {
            // Get Connection to SignalR Hub
            var connection = $.hubConnection();
    
            // Create a Proxy
            proxy = connection.createHubProxy('SignalRData');
    
            // Publish the event when server has a push notification
            proxy.on('renewProducts', function (message) {
                console.log("Database SQL Dependency change detectedgnalRGetData: " + message);
                $rootScope.$emit('renewProducts', message);
            });
    
            // Start Connection
            connection.start().done(function () {
                console.log("Conenction Ready - invoke proxy");
                proxy.invoke('SignalRGetData');
            });
    
        };
    
        return {
            initialise: initialise
        }
    }]);
    

    最佳答案

    据我所知,您的代码有两个问题:

  • 每当您的客户端连接到服务器时,它都会调用SignalRGetData。根据您的代码SigalRGetData创建一个
    新的SqlDependency实体。因此,如果您有两个客户,您将
    有两个SqlDependency实体或两个数据库订阅
    意味着您将在每个客户方收到两个通知。如果要在数据库发生更改时为每个客户端发送一个通知,则您的应用程序应该只有一个SqlDependency实体。
  • 根据您的代码,您将仅在第一次数据库更改时收到通知(我知道这很奇怪,但它是true)。如果要连续接收通知,则应重新订阅:


  • SqlDependency具有带有内存泄漏的problems。但是,您可以使用SqlDependencySqlDependencyEx的开源实现。它使用数据库触发器和 native Service Broker通知来接收有关表更改的事件。使用SqlDependecyEx,您可以分别监视INSERTDELETEUPDATE,并在事件args对象中接收实际更改的数据(xml)。这是一个用法示例:

  • int changesReceived = 0;
    using (SqlDependencyEx sqlDependency = new SqlDependencyEx(
              TEST_CONNECTION_STRING, TEST_DATABASE_NAME, TEST_TABLE_NAME))
    {
        sqlDependency.TableChanged += (o, e) => changesReceived++;
        sqlDependency.Start();
    
        // Make table changes.
        MakeTableInsertDeleteChanges(changesCount);
    
        // Wait a little bit to receive all changes.
        Thread.Sleep(1000);
    }
    
    Assert.AreEqual(changesCount, changesReceived);
    

    建议:

    为了避免重复的客户端通知,最好为您的 Controller /应用程序使用一个通知示例。我上一个项目的代码示例:
    public class HomeController : Controller
    {
        // One global subscription for all the controller.
        static HomeController()
        {
            // ITableRowRepository incapsulates SqlDependencyEx usage.
            var repo = (ITableRowRepository)DependencyResolver.Current
                               .GetService(typeof(ITableRowRepository));
            // One global subscription.
            repo.TableChanged += RepoTableChanged;
        }
    
        // Actions here.
    
        private static void RepoTableChanged(object sender, TableChangedEventArgs e)
        {
            // Clients notification here.
        }
    }
    

    希望这可以帮助。

    关于c# - SignalR对sqlDependency的更改重复消息,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29836159/

    10-10 15:25