我正在使用SqlDependency和signalR开发通知系统,我无法处理的问题是当我更改属性值时#34; IsOnline"根据与会者状态,在DB为True或False时,OnChange事件会多次触发,第一次新用户登录时我得到两个通知,然后第二次我得到更多像4然后更多。每次新的登录或退出时,通知的数量都会增加。我确定SqlDependency中的问题不在SignalR中,我将与您分享我的部分代码。
提前致谢。
[System.Web.Services.WebMethod]
public static IEnumerable<AttendeeList> GetAllUsers()
{
var AttendeeList = new List<AttendeeList>();
try
{
using (var connection = new SqlConnection(_connString))
{
connection.Open();
string str = "";
str += "SELECT [AttendeeID], ";
str += " [IsAllowToUploadDocuments],";
str += " [IsOnline], ";
str += " [AttendeeTypeName],";
str += " [UserName] ";
str += " FROM [dbo].[Meeting_Attendees] ";
str += " INNER JOIN [dbo].[aspnet_Users] ON [aspnet_Users].[UserId] = [Meeting_Attendees].[AttendeeID] ";
str += " INNER JOIN [dbo].[AttendeeType] ON [dbo].[AttendeeType].[AttendeeTypeID] = [dbo].[Meeting_Attendees].[AttendeeTypeID] ";
str += " WHERE [MeetingID]=@MeetingID ORDER BY [IsOnline] DESC";
using (var command = new SqlCommand(@str, connection))
{
SqlParameter prm = new SqlParameter("@MeetingID", SqlDbType.Int);
prm.Direction = ParameterDirection.Input;
prm.DbType = DbType.Int32;
prm.Value = Convert.ToInt32(Properties.Settings.Default.MeetingID);
command.Parameters.Add(prm);
command.Notification = null;
var dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependencyUsers_OnChange);
if (connection.State == ConnectionState.Closed)
connection.Open();
var reader = command.ExecuteReader();
while (reader.Read())
{
AttendeeList.Add(item: new AttendeeList { UserName = (string)reader["UserName"], UserType = (string)reader["AttendeeTypeName"], IsOnline = (bool)reader["IsOnline"], IsAllowToUploadDocuments = (bool)reader["IsAllowToUploadDocuments"], IsCurrentUser = true ? (Guid)reader["AttendeeID"] == new Guid(Properties.Settings.Default.UserID.ToString()) : false });
}
}
}
}
catch { }
return AttendeeList;
}
private static void dependencyUsers_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change && e.Info == SqlNotificationInfo.Update)
{
//Call SignalR
MessagesHub.UpdateUsers();
}
}
答案 0 :(得分:2)
要确保事件处理程序已注册一次,请在“ + =”之前执行“-=”:
oDependency.OnChange -= new OnChangeEventHandler(DBUpdateNotificationReeived);
oDependency.OnChange += new OnChangeEventHandler(DBUpdateNotificationReeived);
检查您的SQL表是否没有“更新”正在更新的记录的触发器(除了sqltabledependency之外)。
答案 1 :(得分:0)
如果监控结果集可能已更改,则会触发查询通知,请参阅Understanding When Query Notifications Occur。作为一般规则,您可能会获得比实际数据更改更多的通知:
请注意,SQL Server可能会生成查询通知,以响应不更改数据的事件,或响应不会实际影响查询结果的更改。例如,当UPDATE语句更改查询返回的行之一时,即使对行的更新未更改查询结果中的列,通知也可能会触发。查询通知旨在支持改进的总体目标缓存数据的应用程序的性能。当服务器负载很重时,SQL Server可能会为订阅生成查询通知消息,而不是执行确定查询结果是否已更改的工作。
在您的帖子中是否会导致问题无法分析,特别是不清楚您如何处理更新,以便再生成4个通知。获取4个通知意味着您发布了4个查询以进行通知,因此您的代码中也可能存在问题并且您超额订阅。
阅读Using SQL Trace to Troubleshoot Query Notifications并尝试对正在进行的操作进行问题排查,通知的创建位置和失效位置。
答案 2 :(得分:0)
使用SignalR和SQL Dependency时遇到同样的问题
这条线不止一次被执行。该活动应仅订阅一次。 oDependency.OnChange + = new OnChangeEventHandler(DBUpdateNotificationReeived);
答案 3 :(得分:0)
我的项目中对OnChange
事件的多次调用也遇到了同样的问题,但我使用help counter 变量修复了它。在这个例子中,在我的例子中,示例中的dependencyUsers_OnChange
函数触发两次。
我将计数器变量初始化为全局变量。在&#34;扫描&#34;在任何更改之前您的临时数据的状态,我还将计数器的值设置为0.
按照您的示例,在此步骤之后,在dependencyUsers_OnChange
语句if
处进行了修改:
private static void dependencyUsers_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change && e.Info == SqlNotificationInfo.Update && counter == 0)
{
//Call SignalR
MessagesHub.UpdateUsers();
counter++; //The update is done once
}
else
{
counter = 0; //if the update is needed in the same iteration, please don't update and set the counter to 0
}
}
在您的情况下,解决方案将类似于:
int counter = 0; //initialization of help counter
[System.Web.Services.WebMethod]
public static IEnumerable<AttendeeList> GetAllUsers()
{
var AttendeeList = new List<AttendeeList>();
try
{
using (var connection = new SqlConnection(_connString))
{
connection.Open();
string str = "";
str += "SELECT [AttendeeID], ";
str += " [IsAllowToUploadDocuments],";
str += " [IsOnline], ";
str += " [AttendeeTypeName],";
str += " [UserName] ";
str += " FROM [dbo].[Meeting_Attendees] ";
str += " INNER JOIN [dbo].[aspnet_Users] ON [aspnet_Users].[UserId] = [Meeting_Attendees].[AttendeeID] ";
str += " INNER JOIN [dbo].[AttendeeType] ON [dbo].[AttendeeType].[AttendeeTypeID] = [dbo].[Meeting_Attendees].[AttendeeTypeID] ";
str += " WHERE [MeetingID]=@MeetingID ORDER BY [IsOnline] DESC";
using (var command = new SqlCommand(@str, connection))
{
SqlParameter prm = new SqlParameter("@MeetingID", SqlDbType.Int);
prm.Direction = ParameterDirection.Input;
prm.DbType = DbType.Int32;
prm.Value = Convert.ToInt32(Properties.Settings.Default.MeetingID);
command.Parameters.Add(prm);
command.Notification = null;
var dependency = new SqlDependency(command);
counter = 0; //Whenewer the web method is called, set te counter to 0
dependency.OnChange += new OnChangeEventHandler(dependencyUsers_OnChange);
if (connection.State == ConnectionState.Closed)
connection.Open();
var reader = command.ExecuteReader();
while (reader.Read())
{
AttendeeList.Add(item: new AttendeeList { UserName = (string)reader["UserName"], UserType = (string)reader["AttendeeTypeName"], IsOnline = (bool)reader["IsOnline"], IsAllowToUploadDocuments = (bool)reader["IsAllowToUploadDocuments"], IsCurrentUser = true ? (Guid)reader["AttendeeID"] == new Guid(Properties.Settings.Default.UserID.ToString()) : false });
}
}
}
}
catch { }
return AttendeeList;
}
private static void dependencyUsers_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change && e.Info == SqlNotificationInfo.Update && counter == 0)
{
//Call SignalR
MessagesHub.UpdateUsers();
counter++; //The update is done once
}
else
{
counter = 0; //if the update is needed in the same iteration, please don't update and set the counter to 0
}
}
我希望这个想法能对某人有所帮助,我用这个解决方案解决了我项目中的问题。