Windows服务中的SqlDependency未触发

时间:2013-10-01 01:16:18

标签: c# windows-services service-broker sqldependency

我正在尝试使用SqlDependency类监视数据库表的更改。虽然我必须遗漏一些东西。我已经按照我在网上看到的所有示例进行了跟踪,并且我已经回顾了本网站上的所有问题。我只是看不到我错过的东西。以下是我在数据库上运行的初始命令,以启用服务代理并创建队列和服务。

CREATE QUEUE ScheduleChangeQueue
GO

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

ALTER DATABASE [database] SET ENABLE_BROKER

在C#方面,我创建了一个具有单个静态Setup方法的类,该方法被调用以启动该进程。这是代码:

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();
        }
    }
}

我看到代码设置正常并且OnChange方法针对订阅被触发一次,但之后我再也没有看到它。我手动进入数据库并更改LastChangeTime字段,希望它会强制触发事件,但没有任何反应。

有人可以说明我搞砸的地方吗?我看到有些人在网上说这种方式在Windows窗体中运行良好,但是在服务中它们也有一些问题。

1 个答案:

答案 0 :(得分:5)

所以我终于想出了我的问题的答案,我想我应该列出我为达到这一点所采取的所有步骤,以便其他人跟在我后面也会有另一个地方寻找答案,因为我似乎无法在一个地方找到我的所有答案。

首先,我注意到在我的情况下,一旦设置了订阅,OnChange事件就会立即触发。这就是为什么我在检查更改类型,所以我可以忽略这些事件。事实证明,忽略这些事件并不是一件好事,因为那些事件实际上是在试图告诉我一些事情。搜索我的价值观指示我:

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

这非常有价值,因为它帮助我看到数据库中的某些选项一定存在问题。经过进一步检查,我注意到我的数据库设置为SQL Server 2000兼容性。这显然是我的第一个问题,因为这是一个2005年的更大功能。所以我尝试将我的设置更改为高版本。这工作正常,但后来我仍然注意到我收到了同样的事件。所以我检查了我的数据库设置,发现它们没有设置为匹配运行服务代理所需的选项。您可以在此处查看所有必需的选项设置:

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

在我检查了所有这些并尝试做一些变通方法以获得正确的设置后,所有设置仍然失败。但这次它失败了,因为更新不会保存。事实证明,客户端在相关表上有触发器,并且用于执行触发器的数据库设置与运行QueryNotifications所需的设置冲突。

长话短说,客户决定他们不想改变所有使用的触发器,因此他们放弃了努力。但是我学到了很多关于如何解决SqlDependency和ServiceBroker的问题。希望我提供的这些链接对其他人有用。评论中提到了一些非常有用的链接,但我将在这个答案中重新发布它们,以便您可以查看其他一些项目。

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

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