Question

I am trying to monitor a database table for changes using the SqlDependency class. Though I must be missing something. I have followed all of the examples that I see online and I have reviewed all the questions on this site. I just don't see what I am missing. Here are the initial commands that I ran on the database to enable the service broker and create the queue and service.

CREATE QUEUE ScheduleChangeQueue
GO

CREATE SERVICE ScheduleChangeService ON QUEUE ScheduleChangeQueue ([http://schemas.microsoft.com/SQL/Notifications/PostQueryNotification])
GO

ALTER DATABASE [database] SET ENABLE_BROKER

On the C# side, I have created a class that has a single static Setup method that is called to initiate the process. Here is the code for that:

public class SqlDependencyManager
{
    private static bool DoesUserHavePermission()
    {
        var success = false;
        try
        {
            Program.Log.Info("Retrieving SqlPermission to establish dependency...");

            var clientPermission = new SqlClientPermission(System.Security.Permissions.PermissionState.Unrestricted);

            // this will throw an error if the user does not have the permissions  
            clientPermission.Demand();

            success = true;

            Program.Log.Info("SqlPermission established. Continue setting up dependency.");
        }
        catch (Exception ex)
        {
            Program.Log.Error(ex, "SqlPermission not able to be established.");
        }

        return success;
    }

    public static void Setup()
    {
        if (!DoesUserHavePermission())
        {
            return;
        }

        var connectionString = ConfigurationManager.ConnectionStrings["ShowMakerPro"].ConnectionString;

        // You must stop the dependency before starting a new one. 
        // You must start the dependency when creating a new one. 
        SqlDependency.Stop(connectionString);
        SqlDependency.Start(connectionString);

        using (var cn = new SqlConnection(connectionString))
        {
            using (var cmd = cn.CreateCommand())
            {
                cmd.CommandType = CommandType.Text;
                //cmd.CommandText = "SELECT MAX(LastChangeTime) FROM Schedule WHERE ChannelID IN ( SELECT ID FROM Channels WHERE Type = 1 ) AND StartTime BETWEEN (GETDATE() - 7) AND (GETDATE() + 30)";
                cmd.CommandText = "SELECT LastChangeTime FROM dbo.Schedule";
                cmd.Notification = null;

                // Creates a new dependency for the SqlCommand. Then creates attaches handler for the notification of data changes
                new SqlDependency(cmd).OnChange += SqlDependency_OnChange;

                cn.Open();

                cmd.ExecuteReader();
            }
        }

        Program.Log.Info("SQL Dependency set. Now monitoring schedule table for changes.");
    }

    private static void SqlDependency_OnChange(object sender, SqlNotificationEventArgs e)
    {
        if (e.Type == SqlNotificationType.Change)
        {
            // this will remove the event handler since the dependency is only for a single notification
            ((SqlDependency)sender).OnChange -= SqlDependency_OnChange;

            ScheduleOutputterService.BuildSchedules();

            Program.Log.Info("SQL Dependency triggered schedule rebuild. Resetting SqlDependency to monitor for changes.");

            Setup();
        }
    }
}

I see the code get setup ok and the OnChange method is fired once for the Subscribe but then I never see it fire after that. I manually go into the database and change the LastChangeTime field hoping that it will force the firing of the event but nothing happens.

Can someone please shed some light on where I am screwing up? I see some people saying on line that this works fine in a windows form but they are also having some problems while in a service.

Was it helpful?

Solution

So I finally figured out the answer to my question and I thought I should list all the steps I took to get to this point so someone else coming along behind me will also have another place to look for answers since I seemed unable to find all of my answers in one place.

First off, I noticed in my situation that as soon as the subscription was set the OnChange event would fire right away. That is why I put in the check for change type so I could ignore those events. It turns out that ignoring those events was not a good thing because those events were actually trying to tell me something. Doing a search on my values directed me here:

http://msmvps.com/blogs/siva/archive/2011/11/22/subtle-sqldependency-notification-issue.aspx

This was very valuable because it helped me to see that there must have been a problem with some of my options in the database. Upon further inspection I noticed that my database was set to SQL Server 2000 compatibility. That is obviously my first problem because this is a 2005 and greater feature. So I tried to change my settings to the high version. This worked ok but then I still noticed that I was receiving the same event. So then I checked my database settings and I found that they were not set to match the options required to run service broker. You can see all the required option settings here:

http://msdn.microsoft.com/en-us/library/ms181122(v=SQL.100).aspx

After I inspected all these and tried to do some workarounds to get the right settings all squared away the setup was still failing. But this time it was failing because the updates would not save. It turned out that the client had triggers on the table in question and it's database settings that were being used to execute the trigger were in conflict with the needed settings to run QueryNotifications.

So long story short, the client decided that they did not want to change all the triggers that were being used so they abandoned the effort. But I learned a lot about how to troubleshoot SqlDependency and ServiceBroker. Hopefully these few links I provided will be helpful for someone else. A couple more links that were very helpful were mentioned in the comments but I am going to repost them in this answer so you can have some other items to review.

http://rusanu.com/2006/06/17/the-mysterious-notification/

http://rusanu.com/2005/12/20/troubleshooting-dialogs/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top