I have followed some tutorial to send notification to my app when something changes in a table in my SQL Server database. This is my listener class:
class dbListener
{
public dbListener()
{
Debug.WriteLine(MainWindow.dbContext.Database.Connection.ConnectionString + "Password=xxx;");
SqlDependency.Stop(MainWindow.dbContext.Database.Connection.ConnectionString + "Password=xxx;");
SqlDependency.Start(MainWindow.dbContext.Database.Connection.ConnectionString + "Password=xxx;");
connection = new SqlConnection(MainWindow.dbContext.Database.Connection.ConnectionString + "Password=xxx;");
connection.Open();
SomeMethod();
}
SqlConnection connection;
void SomeMethod()
{
// Assume connection is an open SqlConnection.
// Create a new SqlCommand object.
SqlCommand command = new SqlCommand("SELECT CODVEI FROM dbo.ArchivioErogazioni", connection);
// Create a dependency and associate it with the SqlCommand.
command.Notification = null; // ---> DO I NEED IT??
SqlDependency dependency = new SqlDependency(command);
// Maintain the refence in a class member.
// Subscribe to the SqlDependency event.
dependency.OnChange += new OnChangeEventHandler(OnDependencyChange);
// Execute the command.
command.ExecuteReader();
}
// Handler method
void OnDependencyChange(object sender, SqlNotificationEventArgs e)
{
// Handle the event (for example, invalidate this cache entry).
MessageBox.Show("ikjkjkj");
Debug.WriteLine("fkldjkfjklgjf");
SomeMethod();
}
void Termination()
{
// Release the dependency.
SqlDependency.Stop(MainWindow.GetConnectionString("Model"));
}
}
It doesn't fire the event correctly. At the start of the app, it shows me the message box (it is in the event management to test it) once or twice, I don't know why. Then, when I edit the values in the database from SQL Server Management Studio, I get the message box or 0 or 1 or 2 times, then it never fires again.
In my database, I have execute this script:
USE master ;
GO
ALTER DATABASE IN4MATICSystem_Pie SET ENABLE_BROKER WITH ROLLBACK IMMEDIATE
GO
ALTER AUTHORIZATION ON DATABASE::IN4MATICSystem_Pie to sa;
I have surely done a big mistake..... which one??
UPDATE:
After the hints of T McKeown, this is my code (still not working, it shows me 2 or 3 message boxes at startup and then nothing):
class dbListener
{
public dbListener()
{
Debug.WriteLine(MainWindow.dbContext.Database.Connection.ConnectionString + "Password=xxx;");
SqlDependency.Stop(MainWindow.dbContext.Database.Connection.ConnectionString + "Password=xxx;");
SqlDependency.Start(MainWindow.dbContext.Database.Connection.ConnectionString + "Password=xxx;");
connection = new SqlConnection(MainWindow.dbContext.Database.Connection.ConnectionString + "Password=xxx;");
connection.Open();
SomeMethod();
}
SqlConnection connection;
SqlCommand command;
void SomeMethod()
{
// Assume connection is an open SqlConnection.
// Create a new SqlCommand object.
if (command == null)
{
command = new SqlCommand("SELECT * FROM dbo.ArchivioErogazioni", connection);
// Create a dependency and associate it with the SqlCommand.
}
else
{
command.Notification = null; // this cancels any previous notifcation object
}
SqlDependency dependency = new SqlDependency(command);
// Maintain the refence in a class member.
// Subscribe to the SqlDependency event.
dependency.OnChange += new OnChangeEventHandler(OnDependencyChange);
// Execute the command.
command.ExecuteReader();
}
// Handler method
void OnDependencyChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change)
{
// Handle the event (for example, invalidate this cache entry).
MessageBox.Show("ikjkjkj");
Debug.WriteLine("fkldjkfjklgjf");
SqlDependency dependency = (SqlDependency)sender;
dependency.OnChange -= OnDependencyChange;
//dependency.OnChange -= OnDependencyChange;
SomeMethod();
}
}
void Termination()
{
// Release the dependency.
SqlDependency.Stop(MainWindow.GetConnectionString("Model"));
connection.Close();
}
}
Try this:
void OnDependencyChange(object sender, SqlNotificationEventArgs e)
{
// Handle the event (for example, invalidate this cache entry).
MessageBox.Show("ikjkjkj");
Debug.WriteLine("fkldjkfjklgjf");
SqlDependency dependency =
(SqlDependency)sender;
dependency.OnChange -= OnDependencyChange;
SomeMethod(); //re-register
}
Modify SomeMethod():
SqlConnection connection;
SqlCommand command; <-- make command instance var
void SomeMethod()
{
// Assume connection is an open SqlConnection.
// Create a new SqlCommand object.
if ( command == null )
{
command = new SqlCommand("SELECT * FROM dbo.ArchivioErogazioni", connection);
// Create a dependency and associate it with the SqlCommand.
}
else{
command.Notification = null; // this cancels any previous notifcation object
}
SqlDependency dependency = new SqlDependency(command);
// Maintain the refence in a class member.
// Subscribe to the SqlDependency event.
dependency.OnChange += new OnChangeEventHandler(OnDependencyChange);
// Execute the command.
command.ExecuteReader();
}
Call this function, does it return true?
private bool CanRequestNotifications()
{
// In order to use the callback feature of the
// SqlDependency, the application must have
// the SqlClientPermission permission.
try
{
SqlClientPermission perm =
new SqlClientPermission(
PermissionState.Unrestricted);
perm.Demand();
return true;
}
catch
{
return false;
}
}
Related
After struggling with this issue from past 3 day, finally I'm putting my problem here.
I'm trying to build a real time application using SignalR and SqlDependency. Apparently, SQLDependency is not working. However, my SignalR is working fine as I've tried many functions that do not require Database interactions.
Below is my code. Here is I'm taking reference from.
Global.asax.cs
public class MvcApplication : System.Web.HttpApplication
{
NotificationHub objNotificationHub;
protected void Application_Start()
{
string connectionString = WebConfigurationManager.AppSettings["SQL"];
// SQL Command Text
string commandText = "SELECT status From tableTask";
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(commandText, connection);
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
SqlDependency.Start(connectionString);
command.ExecuteReader().Dispose();
objNotificationHub = new NotificationHub();
}
}
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change)
{
objNotificationHub.SendNotifications();
}
}
}
NotificationHub.cs (SignalR Hub Class)
[HubMethodName("sendNotifications")]
public void SendNotifications()
{
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();
context.Clients.All.recieveNotification("asbc");
}
My SqlDependency.OnChange event i.e. dependency_OnChange is not firing
on database update.
I've tried all the methods like granting permissions
ALTER DATABASE MyDB SET ENABLE_BROKER
and many others like this.
But no success.
Could there be anything that I'm missing. Also, is there any way to check if my code is communicating with SQL Server?
TIA
You are not executing your command, and that is needed to get notification:
SqlDependency.Start(connectionString);
string commandText = "SELECT status From dbo.tableTask"; // don't forget schema here
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command = new SqlCommand(commandText, connection);
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
command.ExecuteReader().Dispose();
objNotificationHub = new NotificationHub();
}
Ensure that you understand how those dependencies work (for example - after you receive one notification - you need to re-register to get subsequent). Or better, use some wrapper library, like this one.
You can test it with this simple example:
static void Main(string[] args) {
var cs = "connection string";
using (SqlConnection connection = new SqlConnection(cs))
{
connection.Open();
SqlCommand command = new SqlCommand("select ErrorCode from dbo.Error", connection);
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += OnChange;
SqlDependency.Start(cs);
command.ExecuteReader().Dispose();
}
Console.ReadKey();
}
private static void OnChange(object sender, SqlNotificationEventArgs e) {
Console.WriteLine(e.Info);
}
I'm new to the concept of query notifications with SQL Server and it's going to take some time for me to wrap my head around it.
My objective is to create a Windows service application that is notified when a change has been made to a SQL Server table. I followed this guide which was helpful in getting me started.
However I'm not able to get the expected result. The OnStart() method in my windows service app looks like so:
protected override void OnStart(string[] args)
{
eventLog1.WriteEntry("Service Started");
serviceRun = false;
SqlClientPermission perm = new SqlClientPermission(System.Security.Permissions.PermissionState.Unrestricted);
try
{
perm.Demand();
eventLog1.WriteEntry("permission granted");
}
catch (System.Exception)
{
eventLog1.WriteEntry("permission denied");
}
try
{
connstr = "Data Source=THSSERVER-LOCAL;Initial Catalog=ET;User ID=mujtaba;Password=ths123";
connection = new SqlConnection(connstr);
SqlCommand command = new SqlCommand("select * from dbo.Customer_FileUploads", connection);
// Create a dependency and associate it with the SqlCommand.
SqlDependency dependency = new SqlDependency(command);
// Maintain the reference in a class member.
// Subscribe to the SqlDependency event.
dependency.OnChange += Dependency_OnChange;
SqlDependency.Start(connstr);
connection.Open();
// Execute the command.
using (SqlDataReader reader = command.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
//eventLog1.WriteEntry("reading data");
}
}
else
{
eventLog1.WriteEntry("No rows found.");
}
reader.Close();
}
}
catch (Exception e)
{
eventLog1.WriteEntry("Error Message: " + e.Message);
}
}
The event SqlDependency is subscribed to, looks like so:
private void Dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
// Handle the event.
eventLog1.WriteEntry("data changed");
}
The OnStop() method looks like so:
protected override void OnStop()
{
SqlDependency.Stop(connstr);
connection.Close();
eventLog1.WriteEntry("In onStop.");
}
I have ENABLE_BROKER set to true in my database. The end result is, The service runs and the followings logs are created:
"Service Started"
"permission granted"
"data changed"
However when I insert new data into the table, the OnChange() event doesn't fire and no new log is created. Also when I stop and start the service again, the OnChange() is triggered even though there was no new data inserted.
Can anyone help me understand the process?
The SqlDependency is removed after the event fires so you need to execute the command again with the dependency. Below is a console app example that will subscribe again unless the notification was due to an error.
using System;
using System.Data;
using System.Data.SqlClient;
namespace SqlDependencyExample
{
class Program
{
static string connectionString = #"Data Source=.;Initial Catalog=YourDatabase;Application Name=SqlDependencyExample;Integrated Security=SSPI";
static void Main(string[] args)
{
SqlDependency.Start(connectionString);
getDataWithSqlDependency();
Console.WriteLine("Waiting for data changes");
Console.WriteLine("Press enter to quit");
Console.ReadLine();
SqlDependency.Stop(connectionString);
}
static DataTable getDataWithSqlDependency()
{
using (var connection = new SqlConnection(connectionString))
using (var cmd = new SqlCommand("SELECT Col1, Col2, Col3 FROM dbo.MyTable;", connection))
{
var dt = new DataTable();
// Create dependency for this command and add event handler
var dependency = new SqlDependency(cmd);
dependency.OnChange += new OnChangeEventHandler(onDependencyChange);
// execute command to get data
connection.Open();
dt.Load(cmd.ExecuteReader(CommandBehavior.CloseConnection));
return dt;
}
}
// Handler method
static void onDependencyChange(object sender,
SqlNotificationEventArgs e)
{
Console.WriteLine($"OnChange Event fired. SqlNotificationEventArgs: Info={e.Info}, Source={e.Source}, Type={e.Type}.");
if ((e.Info != SqlNotificationInfo.Invalid)
&& (e.Type != SqlNotificationType.Subscribe))
{
//resubscribe
var dt = getDataWithSqlDependency();
Console.WriteLine($"Data changed. {dt.Rows.Count} rows returned.");
}
else
{
Console.WriteLine("SqlDependency not restarted");
}
}
}
}
I have two tables in my db, one that records exceptions, and another that records log messages.
I am leveraging the SqlDependency object to be notified when those tables change so that I can update my web dashboard. I got this working:
public IEnumerable<ElmahException> GetExceptions()
{
using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["elmah-sqlserver"].ConnectionString))
{
connection.Open();
using (SqlCommand command = new SqlCommand(#"SELECT [ErrorId],[Application],[Host],[Type],[Source],[Message],[User],[StatusCode],[TimeUtc],[Sequence],[AllXml]
FROM [dbo].[ELMAH_Error] ORDER BY [TimeUtc] desc", connection))
{
// Make sure the command object does not already have
// a notification object associated with it.
command.Notification = null;
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(ELMAHdependency_OnChange);
if (connection.State == ConnectionState.Closed)
connection.Open();
using (var reader = command.ExecuteReader())
return reader.Cast<IDataRecord>()
.Select(x => new ElmahException()
{
ErrorId = x.GetGuid(0),
Application = x.GetString(1),
Host = x.GetString(2),
Type = x.GetString(3),
Source = x.GetString(4),
Error = x.GetString(5),
User = x.GetString(6),
Code = x.GetInt32(7),
TimeStamp = x.GetDateTime(8).ToString().Replace("T", " ")
}).ToList();
}
}
}
private void ELMAHdependency_OnChange(object sender, SqlNotificationEventArgs e)
{
Console.Write("Exception table changed!");
}
This is working well, so with the wind in my sails, I then took a crack at doing something similar for the log messages:
public IEnumerable<LogMessage> GetLogMessages()
{
using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["elmah-sqlserver"].ConnectionString))
{
connection.Open();
using (SqlCommand command = new SqlCommand(#"SELECT [application],[time_stamp],[logLevel],[logger],[message]
FROM [dbo].[LogTable] ORDER BY [time_stamp] desc", connection))
{
// Make sure the command object does not already have
// a notification object associated with it.
command.Notification = null;
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(NLOGdependency_OnChange);
if (connection.State == ConnectionState.Closed)
connection.Open();
using (var reader = command.ExecuteReader())
return reader.Cast<IDataRecord>()
.Select(x => new LogMessage()
{
Application = x.GetString(0),
TimeStamp = x.GetDateTime(1).ToString().Replace("T", " "),
LogLevel = x.GetString(2),
Logger = x.GetString(3),
Message = x.GetString(4)
}).ToList();
}
}
}
private void NLOGdependency_OnChange(object sender, SqlNotificationEventArgs e)
{
Console.Write("Log table has changed!");
}
At this point, I am alerted only to when the log table has changed. With this additional SqlDependency in the mix, ELMAHdependency_OnChange never gets called. If I comment out my GetLogMessages() method, then ELMAHdependency_OnChange is called once more.
It looks like multiple SqlDependency objects are mutually exclusive. Any ideas on how I can monitor two tables at the same time?
It is possible to concatenate another SqlStatement using a semicolon.
Here's a snippet from your code, with my changes.
[...]
connection.Open();
var queries = new [] {#"SELECT [application],[time_stamp],[logLevel],[logger],[message] FROM [dbo].[LogTable] ORDER BY [time_stamp] desc",
#"SELECT [ErrorId],[Application],[Host],[Type],[Source],[Message],[User],[StatusCode],[TimeUtc],[Sequence],[AllXml] FROM [dbo].[ELMAH_Error] ORDER BY [TimeUtc] desc"};
using (SqlCommand command = new SqlCommand(string.Join("; ", queries), connection))
{
[...]
It's also important to re-register the SqlDependency once it has called the event. Or else the event is only triggered once..
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
SqlDependency dependency = sender as SqlDependency;
if (dependency != null) dependency.OnChange -= dependency_OnChange;
if (e.Type == SqlNotificationType.Change)
{
// Do things
}
SetupDatabaseDependency();
}
SetupDatabaseDependency() would contain the code to set up the SqlDependency.
Use a stored procedure that selects from both tables instead of a query.
CREATE PROCEDURE [dbo].[SQLDependency_TestTable1_TestTable2]
#MaxIdxTestTable1 INT = 1, #MaxIdxTestTable2 INT = 1
AS
-- Don't do this - SQLDependency doesn't like.
--SET TRANSACTION ISOLATION LEVEL READ COMMITTED
-- Don't do this either - SQLDependency doesn't like.
--SELECT MAX(ID) FROM ehmetrology.TestTable1
--SELECT COUNT(ID) FROM ehmetrology.TestTable1
-- See here for a whole list of things SQLDependency doesn't like:
-- stackoverflow.com/questions/7588572/what-are-the-limitations-of-sqldependency/7588660#7588660
SELECT DCIdx FROM TestTable1 WHERE Idx >= #MaxIdxTestTable1
ORDER BY DCIdx DESC;
SELECT DCIdx FROM TestTable2 WHERE Idx >= #MaxIdxTestTable2
ORDER BY DCIdx DESC;
GO
And then do this on the .NET side (pardon the VB):
Using adapter As New SqlDataAdapter(mSQLD_Command)
adapter.Fill(mSQLD_DataSet, SQLD_DATASET_TABLENAME)
End Using
' Reload the dataset that's bound to the grid.
If mSQLD_DataSet.Tables.Count = 2 Then
Dim iTest1Index As Integer = 0
Dim iTest2Index As Integer = 0
If Integer.TryParse(mSQLD_DataSet.Tables(0).Rows(0).Item(0).ToString, iTest1Index) Then
If iTest1Index<> moTest1.MaxDCIdx Then
GetTest1Data(True)
End If
End If
If Integer.TryParse(mSQLD_DataSet.Tables(1).Rows(0).Item(0).ToString, iTest2Index) Then
If iTest2Index <> moTest2.MaxDCIdx Then
GetTest2Data()
End If
End If
End If
By using a stored procedure, you don't have all those records moving around as you do with a consistent select statement. You'll get notified each time either one of the 2 tables are modified, so you have to dig into the result to figure out which one has changed.
I have just copied the example from an official Microsoft source http://msdn.microsoft.com/en-us/library/a52dhwx7(v=vs.80).aspx and I am baffled by it. Having run the application, it makes constant database hits even though nothing is using that table? I thought when that table actually changes the event will fire? I don't want it to make constant DB calls every second, that is awful.
Have I done something wrong? I imagine I have not sure what though. Anybody have a link to a good example preferably not MSDN.
Thanks in advance, Onam.
This is the SQL:
return "SELECT [ID],[FromMachine],[FromStore],[FromUser] FROM dbo.Store_Message";
As requested, all code:
public partial class Form1 : Form
{
string connectionString = "server=localhost;database=usicoal;uid=admin;password=";
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
GetNames();
}
private bool DoesUserHavePermission()
{
try
{
SqlClientPermission clientPermission = new SqlClientPermission(PermissionState.Unrestricted);
clientPermission.Demand();
return true;
}
catch
{
return false;
}
}
void dep_OnChange(object sender, SqlNotificationEventArgs e)
{
if (this.InvokeRequired)
{
this.BeginInvoke(new MethodInvoker(GetNames));
}
else
{
GetNames();
}
SqlDependency dep = sender as SqlDependency;
dep.OnChange -= new OnChangeEventHandler(dep_OnChange);
}
private void GetNames()
{
if (!DoesUserHavePermission())
return;
SqlDependency.Stop(connectionString);
SqlDependency.Start(connectionString);
using (SqlConnection cn = new SqlConnection(connectionString))
{
using (SqlCommand cmd = cn.CreateCommand())
{
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT ID FROM dbo.[BTE_SIMPLE_STORE_MESSAGE]";
cmd.Notification = null;
SqlDependency dep = new SqlDependency(cmd);
dep.OnChange += new OnChangeEventHandler(dep_OnChange);
cn.Open();
using (SqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
}
}
}
}
}
}
SqlDependency usually works as you expected it. It fires events if something was changed in your db. Constant calls occure if something is wrong with your query. It's important to use the full two part table name (e.g. dbo.TableName).
The MSDN documentation is not as bad - have a look at this more up-to-date article or this one version.
Found that the above code was fine when I:
Right click database select properties
Select options
Set compatibility level to SQL Server 2008(100)
OK
Bang the code works correctly.
I'm working with SQLDependency to notify me if there is a change in the Database.
After Program Start-Up it works just fine. When I make a first change the Event fires. Wohoo... that's great.
But if I made a second change the event doesn't fire again. I've searched all the web I think but haven't found anything about THIS Problem. Only found problems where the OnChange-Event fires in a Loop.
Can anyone help me?
Here a little code piece:
private void GetStates()
{
if (!DoesUserHavePermission())
return;
SqlDependency.Stop(con);
SqlDependency.Start(con);
using (SqlConnection cn = new SqlConnection(con))
{
using (SqlCommand cmd = cn.CreateCommand())
{
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT Bla, Bla2, ..FROM dbo.[BLA3]"
cmd.Notification = null;
cmd.Dispose();
SqlDependency dep = new SqlDependency(cmd);
dep.OnChange += new OnChangeEventHandler(dep_OnChange);
cn.Open();
using (SqlDataReader dr = cmd.ExecuteReader())
{
state.Clear(); //In this Case "state" is a List<string>
while (dr.Read())
{
state.Add(dr.GetString(0) + "|" + dr.GetInt32(3));
}
dr.Dispose();
dr.Close();
}
}
}
}
my OnChange-Event looks like this:
private void dep_OnChange(object sender, SqlNotificationEventArgs e)
{
SqlDependency dep = sender as SqlDependency;
dep.OnChange -= this.dep_OnChange;
using (SqlConnection cn = new SqlConnection(con))
{
using (SqlCommand cmd = cn.CreateCommand())
{
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT Bla, Bla2, ..FROM dbo.[BLA3]";
cmd.Notification = null;
if (e.Type == SqlNotificationType.Change)
{
if (cn.State != ConnectionState.Open)
{
cn.Open();
}
using (SqlDataReader dr = cmd.ExecuteReader())
{
state.Clear(); // Clear and Refill the stringlist "state"
while (dr.Read())
{
state.Add(dr.GetString(0) + "|" + dr.GetInt32(3));
}
}
}
cn.Close();
}
}
this.GetStates(); //to go ahead and wait for a new change
}
Where is the problem?
I was running into this issue as well. You need to create a new SqlDependency entity (after unsubscribing the existing one from the OnChange event) and then run a new ExecuteReader command. I got the idea from this post:
http://www.codeproject.com/Articles/12335/Using-SqlDependency-for-data-change-events
This usually makes sense, as once you have been notified of a change you will normally want to re-query the data.
After changes happened to the database at the first time, you have to execute the command again and re-subscribe to the event.
The following code is working for me.
class Program
{
static string connectionString = "Server=.;Database=test_sql_dependency;Integrated Security=True;";
static void Main(string[] args)
{
// 1. create database
// 2. enable service broker by executing this sql command on the database.
// alter database test_sql_dependency set enable_broker
// 3. start sql dependency, for some sql server connection string or with queue if you want.
//var queueName = "myFirstQueue";
//SqlDependency.Start(connectionString, queueName);
SqlDependency.Start(connectionString);
// complete the rest of the steps in seperate method to be able to call it again when you need to
// re-subscribe to the event again, becuase by default it will be executed only one time
RegisterSqlDependency();
Console.WriteLine("Listening to database changes...");
Console.ReadLine();
}
static void RegisterSqlDependency()
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
if (connection.State != System.Data.ConnectionState.Open)
{
connection.Open();
}
// 4. create a sql command
// you can't say select *, and also you have to specefy the db owner (dbo.)
SqlCommand command = new SqlCommand("select Id, Name from dbo.Employee", connection);
// 5. create dependency and associtate it to the sql command
SqlDependency dependency = new SqlDependency(command);
// 6. subscribe to sql dependency event
dependency.OnChange += new OnChangeEventHandler(OnDependencyChange);
// 7. execute the command
using (SqlDataReader reader = command.ExecuteReader())
{
}
}
}
static void OnDependencyChange(object sender, SqlNotificationEventArgs e)
{
var InsertOrUpdateOrDelte = e.Info;
//-----------------------------Finally-------------------------
// after you knew that there is a change happened
// you have to unsubscribe the event and execute the command again and then re-subscribe to the event
// 1. unsubscribe the event
SqlDependency dependency = sender as SqlDependency;
dependency.OnChange -= OnDependencyChange;
// 2. re-subscribe to the event and execute the command again
RegisterSqlDependency();
}
}
In your private void dep_OnChange(object sender, SqlNotificationEventArgs e) method after you unsubscribe the dep_OnChange event you should call the private void GetStates() again, to initialize the dep.OnChange event again.
Not sure if that is your problem but you dispose the command right after you have created it:
using (SqlCommand cmd = cn.CreateCommand())
{
...
cmd.Dispose();
It looks like a bug.
In GetStates() :
SqlDependency.Stop(con);
SqlDependency.Start(con);
these lines should be executed only when registering the sql dependency for first time.
Restrict them when you call the method from OnChange event.
Look my friend:
dep.OnChange -= this.dep_OnChange;
you un-fired your event; which is not true;
just delete this line;