我在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);
}
}
}
答案 0 :(得分:0)
实际问题不是解雇事件。问题是“labelText.Text”无法在主线程上工作。
此代码解决了我的问题:
labelText.Invoke((MethodInvoker)delegate {
labelText.Text = e.Info.ToString() + ": " + e.Type.ToString();
});