我开发了一个网页,该网页连接到signalR集线器,并使用angularjs挂接到jQuery代码中。发生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
实体。 SqlDependency
具有带有内存泄漏的problems。但是,您可以使用SqlDependency
类SqlDependencyEx的开源实现。它使用数据库触发器和 native Service Broker通知来接收有关表更改的事件。使用SqlDependecyEx
,您可以分别监视INSERT
,DELETE
,UPDATE
,并在事件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/