Getting started with query notifications
08 Mar 2010The SqlDependency class was introduced in .NET 2.0, but still there are many developers not aware of this functionality, or many not using it because it can be somewhat cumbersome to make it work properly.
This class gives you the ability to create a dependency between your application and SQL server 2005/2008, which in turn will notify your application whenever the result set of your query changes. This is ideal for scenarios that involve caching or where you normally would use some sort of polling mechanism.
It’s worth that the applications that will benefit the most from query notifications are those that mostly read data and where updates are infrequent. This is because query notification introduces an overhead, as it has to check for active subscribers, and raise notifications, whenever the table data is altered.
Database permissions
This is the part that causes most of the trouble for people trying to get query notifications working. It can be very hard to troubleshoot what’s wrong, because quite often you get no error message at all, stating what the possible cause is. The SQL statements below should make sure you’re good to go.
Open up your query window and run the following command, to make sure you’re working against the correct database:
The first thing you need to check is that the service broker on your SQL server is running. This is is done by running the command below, which should return “1”.
If the command above returned “0” you need to run the command below, then rerun the command above to make sure it now returns “1”:
Then you need to give the database user you’re going to use in your application some permissions, to allow it to create the needed procedure, queue and service:
GRANT CREATE QUEUE TO DatabaseUser
GRANT CREATE SERVICE TO DatabaseUser
You then need to allow your user to be able to subscribe to query notifications, by running the following command. Make sure that the database user is the same as you’re specifying in your connection string.
To successfully register a notification, the database user needs SELECT privileges on the table that it’s trying to query. You only need to do this if your login isn’t sysadmin or db_owner. The schema value below will for the majority of people be “dbo”.
The last permission you will have to give the database user is to allow it to receive notifications sent to the message queue by SQL server:
To make sure that all the permissions have been granted, you can run the following command in the query window:
Some code please!
In this example I’m going to create a simple console application that will receive query notifications. Exception handling is not implemented in this example, to keep it simple.
The first thing we’re doing is checking that we’re allowed to request notifications. If we’re allowed to do that we start listening for notifications from the SQL server specified in the connection string. We then register our dependency, which is done by specifying an SQL query and associating an instance of the SqlDependency class with our SqlCommand instance. The code is shown below…
{
if (CanRequestNotifications())
{
SqlDependency.Start(ConnectionString);
Console.WriteLine("Started the listener...");
RegisterDependency();
Console.WriteLine("Press enter to quit...");
Console.ReadLine();
Console.WriteLine("Stopping the listener...");
SqlDependency.Stop(ConnectionString);
}
else
Console.WriteLine("Not allowed to request notifications!");
}
This method will return true if all the correct permissions are set.
{
SqlClientPermission permission = new SqlClientPermission(PermissionState.Unrestricted);
try
{
permission.Demand();
return true;
}
catch (Exception)
{
return false;
}
}
This method will register the dependency with the SQL server and hook up an event handler, which will be invoked whenever the result set of the SQL query you’ve specified has changed. There as some restrictions on what type of queries you can specify, read more about the limitations here.
{
using (SqlConnection connection = new SqlConnection(ConnectionString))
{
SqlCommand command = new SqlCommand("select Id from dbo.table", connection) { Notification = null };
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += DependencyOnChange;
connection.Open();
SqlDataReader dr = command.ExecuteReader(CommandBehavior.CloseConnection);
if (dr != null)
{
// Cache or display the data if you need to
dr.Close();
}
}
}
This is the method that will be invoked whenever the result set of your query has changed. As you can see we need to unhook the event handler and then register a new one.
A query notification will be sent if any of the following events occur:
- Rows contained in the query results may have changed.
- The subscription expires.
- The server restarts.
- The query notification subscription could not be created (for example, the SELECT statement does not conform to the requirements specified in Creating a Query for Notification.
- The server is heavily loaded.
- Objects that the subscription depends on are dropped or modified.
{
SqlDependency dependency = (SqlDependency)sender;
dependency.OnChange -= DependencyOnChange;
Console.WriteLine(DateTime.Now.ToLongTimeString() +
" Info:" + e.Info +
" Type:" + e.Type +
" Source:" + e.Source);
RegisterDependency();
}
That’s it! You should now be able to enjoy the benefits of query notification in your own applications!