【问题标题】:SQL Dependency not firing with windows formSQL Dependency 未使用 Windows 窗体触发
【发布时间】:2017-05-01 06:28:54
【问题描述】:

我遇到了 Windows 窗体应用程序的 SQL 依赖问题。我在source site 找到了一个例子。这个例子作为一个 c# 终端应用程序工作得很好,但是当我将它修改为一个 win 表单应用程序时,它不会触发 SQL 依赖项。

这里是 sql db 脚本:

USE master

-- Cleaning up before we start
IF  EXISTS (SELECT name FROM sys.databases WHERE name = N'SqlDependencyTest')
DROP DATABASE [SqlDependencyTest]
IF  EXISTS (SELECT * FROM sys.server_principals WHERE name = N'startUser')
DROP LOGIN [startUser]
IF  EXISTS (SELECT * FROM sys.server_principals WHERE name = N'subscribeUser')
DROP LOGIN [subscribeUser]

-- Creating a database
CREATE DATABASE [SqlDependencyTest]
GO

-- Ensuring that Service Broker is enabled 
ALTER DATABASE [SqlDependencyTest] SET ENABLE_BROKER
GO 

-- Creating users
CREATE LOGIN [startUser] WITH PASSWORD=N'startUser', 
            DEFAULT_DATABASE=[SqlDependencyTest], 
            CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF
GO
CREATE LOGIN [subscribeUser] WITH PASSWORD=N'subscribeUser', 
            DEFAULT_DATABASE=[SqlDependencyTest], CHECK_EXPIRATION=OFF, 
            CHECK_POLICY=OFF
GO

-- Switching to our database
use [SqlDependencyTest]

-- Creating a table. All changes made to the contents of this table will be
-- monitored.
CREATE TABLE Users (ID int, Name nvarchar(50))
GO

/*
 * Creating the users in this database
 *
 * We're going to create two users. One called startUser. This is the user 
 * that is going to have sufficient rights to run SqlDependency.Start.
 * The other user is called subscribeUser, and this is the user that is 
 * going to actually register for changes on the Users-table created earlier.
 * Technically, you're not obligated to make two different users naturally, 
 * but I did here anyway to make sure that I know the minimal rights required
 * for both operations
 *
 * Pay attention to the fact that the startUser-user has a default schema set.
 * This is critical for SqlDependency.Start to work. Below is explained why.
 */
CREATE USER [startUser] FOR LOGIN [startUser] 
WITH DEFAULT_SCHEMA = [startUser]
GO
CREATE USER [subscribeUser] FOR LOGIN [subscribeUser]
GO

/*
 * Creating the schema
 *
 * It is vital that we create a schema specifically for startUser and that we
 * make this user the owner of this schema. We also need to make sure that 
 * the default schema of this user is set to this new schema (we have done 
 * this earlier)
 *
 * If we wouldn't do this, then SqlDependency.Start would attempt to create 
 * some queues and stored procedures in the user's default schema which is
 * dbo. This would fail since startUser does not have sufficient rights to 
 * control the dbo-schema. Since we want to know the minimum rights startUser
 * needs to run SqlDependency.Start, we don't want to give him dbo priviliges.
 * Creating a separate schema ensures that SqlDependency.Start can create the
 * necessary objects inside this startUser schema without compromising 
 * security.
 */
CREATE SCHEMA [startUser] AUTHORIZATION [startUser]
GO

/*
 * Creating two new roles. We're not going to set the necessary permissions 
 * on the user-accounts, but we're going to set them on these two new roles.
 * At the end of this script, we're simply going to make our two users 
 * members of these roles.
 */
EXEC sp_addrole 'sql_dependency_subscriber' 
EXEC sp_addrole 'sql_dependency_starter' 

-- Permissions needed for [sql_dependency_starter]
GRANT CREATE PROCEDURE to [sql_dependency_starter] 
GRANT CREATE QUEUE to [sql_dependency_starter]
GRANT CREATE SERVICE to [sql_dependency_starter]
GRANT REFERENCES on 
CONTRACT::[http://schemas.microsoft.com/SQL/Notifications/PostQueryNotification]
  to [sql_dependency_starter] 
GRANT VIEW DEFINITION TO [sql_dependency_starter] 

-- Permissions needed for [sql_dependency_subscriber] 
GRANT SELECT to [sql_dependency_subscriber] 
GRANT SUBSCRIBE QUERY NOTIFICATIONS TO [sql_dependency_subscriber] 
GRANT RECEIVE ON QueryNotificationErrorsQueue TO [sql_dependency_subscriber] 
GRANT REFERENCES on 
CONTRACT::[http://schemas.microsoft.com/SQL/Notifications/PostQueryNotification]
  to [sql_dependency_subscriber] 

-- Making sure that my users are member of the correct role.
EXEC sp_addrolemember 'sql_dependency_starter', 'startUser'
EXEC sp_addrolemember 'sql_dependency_subscriber', 'subscribeUser'

这里是 c# win 表单代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace SqlDependencyTest
{
    public partial class Form1 : Form
    {
        private static string mStarterConnectionString =
@"Data Source=(local);Database=SqlDependencyTest;Persist Security Info=false;
  Integrated Security=false;User Id=startUser;Password=startUser";
        private static string mSubscriberConnectionString =
    @"Data Source=(local);Database=SqlDependencyTest;Persist Security Info=false;
Integrated Security=false;User Id=subscribeUser;Password=subscribeUser";

        public Form1()
        {
            InitializeComponent();

            // Quitting if any exist connection...
            SqlDependency.Stop(mStarterConnectionString);

            // Starting the listener infrastructure...

            SqlDependency.Start(mStarterConnectionString);

            // Registering for changes... 
            RegisterForChanges();



        }

        public void RegisterForChanges()
        {
            // Connecting to the database using our subscriber connection string 
            // and waiting for changes...
            SqlConnection oConnection
                                = new SqlConnection(mSubscriberConnectionString);
            oConnection.Open();
            try
            {
                SqlCommand oCommand = new SqlCommand(
                  "SELECT ID, Name FROM dbo.Users",
                  oConnection);
                SqlDependency oDependency = new SqlDependency(oCommand);
                oDependency.OnChange += new OnChangeEventHandler(OnNotificationChange);

                SqlDataReader objReader = oCommand.ExecuteReader();
                try
                {
                    while (objReader.Read())
                    {
                        // Doing something here...
                        labelText.Text = "reading ok";
                    }
                }
                finally
                {
                    objReader.Close();
                }
            }
            finally
            {
                oConnection.Close();
            }


        }

        public void OnNotificationChange(object caller,
                                            SqlNotificationEventArgs e)
        {
            // Testisting if getting dependency response...
            labelText.Text += e.Info.ToString() + ": " + e.Type.ToString();
            RegisterForChanges();
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            // Quitting...
            SqlDependency.Stop(mStarterConnectionString);
        }
    }
}

【问题讨论】:

  • 当你说它没有触发时,你没有看到你的注册事件被调用吗?您是否附加了调试器以验证它没有被调用?有没有抛出异常?
  • 当我伤心不触发意味着当连接到 winform 应用程序的数据库中的数据发生更改时,应用程序没有调用“OnNotificationChange”,是的,我确实调试了同样的问题......但相同的代码(存在于源站点)终端应用程序工作正常,并在数据库中的数据更改时触发“OnNotificationChange”。
  • 您可以尝试将您最初的RegisterForChanges 调用移动到表单的Load 事件中。
  • 如果触发事件创建与否,我已经尝试再次调试,Windows 窗体的答案也是肯定的。以前有人问过你是我的错,但我想我一开始并没有意识到好......谢谢你提到它。问题是为什么 label.Text 没有设置使用依赖触发操作创建的新文本。

标签: c# winforms sqldependency


【解决方案1】:

实际问题不是触发事件。问题是“labelText.Text”在主线程上不起作用。

这段代码解决了我的问题:

    labelText.Invoke((MethodInvoker)delegate {
        labelText.Text = e.Info.ToString() + ": " + e.Type.ToString();
    });

【讨论】:

  • 是 - 您不能从单独的线程更新表单,因此需要调用。您可以使用Control.InvokeRequired 属性检查是否需要调用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-29
  • 2011-10-30
  • 1970-01-01
  • 1970-01-01
  • 2023-03-24
相关资源
最近更新 更多