我开发了一个连接到signalR hub的网页,它连接到带有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_OnChange
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
}
}]);
答案 0 :(得分:2)
据我所知,您的代码有几个问题:
SignalRGetData
。根据您的代码SigalRGetData
创建一个
新的SqlDependency
实体。因此,如果你有两个客户,你会
有两个SqlDependency
实体或两个数据库订阅
意味着每个客户端都会有两个通知。如果您希望在数据库发生更改时为每个客户端发送一个通知,那么您的应用程序应该只有一个SqlDependency
实体。MSDN包含如何使用SqlDependency here的示例。请注意,与SqlNotification使用情况类似,如果客户端需要进一步通知
,那么客户应该再次订阅
SqlDependency
有problems内存泄漏。 Hovewer,您可以使用SqlDependency
类的开源实现 - SqlDependencyEx。它使用数据库触发器和本机Service Broker通知来接收有关表更改的事件。使用SqlDependecyEx
,您可以分别监控INSERT
,DELETE
,UPDATE
,并接收实际更改的数据(xml
)事件args对象。这是一个用法示例: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);
建议:
为避免重复的客户端通知,最好为控制器/应用程序使用一个通知范例。我上一个项目的代码示例:
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.
}
}
希望这有帮助。
答案 1 :(得分:2)
我有一个解决方案 1.只需使用静态属性bool创建一个Class。
public class OutilContext
{
public static bool first = true;
}
在Global.asax.cs中,您应该控制Session_Start void
if (OutilContext.first == true)
{
OutilContext.first = false;
NotificationComponent NC = new NotificationComponent();
var currentTime = DateTime.Now;
NC.RegisterNotification(currentTime);
}
它控制了许多SqlDependency,因为当客户端访问应用程序时,Global Class为每个客户端创建SqlDependency。