2017-05-01 1 views
0

Ich habe ein Problem mit SQL-Abhängigkeitsproblem mit Windows-Formular-App. Ich habe ein Beispiel gefunden bei source site. Dieses Beispiel funktioniert wie eine C# Terminal-Anwendung, aber wenn ich es als win-Formular-Anwendung modifiziere, feuert es keine SQL-Abhängigkeit.SQL-Abhängigkeit nicht mit Windows-Formular ausgelöst

Hier ist sql db Skript:

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' 

Hier ist C# win Form Code

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

Wenn Sie sagen, dass es nicht feuert, sind Sie nicht Ihre registrierte Ereignis zu sehen, genannt zu werden? Haben Sie einen Debugger angeschlossen, um zu verifizieren, dass er nicht aufgerufen wird? Wird irgendeine Ausnahme ausgelöst? – pstrjds

+0

Wenn ich traurig nicht feuern bedeutet, wenn Daten in der Datenbank geändert, die mit Winform App verbunden ist, Anwendung nicht "OnNotificationChange" aufrufen, und ja ich debuggte es das gleiche Problem ... Aber die gleichen Codes (existiert an der Quellseite) Terminal-Anwendung funktioniert gerade gut und feuert "OnNotificationChange", wenn sich Daten in der Datenbank ändern. – eljava

+0

Sie können versuchen, den ersten 'RegisterForChanges'-Aufruf in das' Load'-Ereignis des Formulars zu verschieben. – pstrjds

Antwort

0

eigentliche Problem nicht Ereignis Brennen wurde. Problem war "labelText.Text" funktioniert nicht auf Haupt-Thread.

Dieser Code fixiert mein Problem:

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

Ja - Sie können ein Formular nicht aus einem separaten Thread aktualisieren, daher muss es aufgerufen werden. Sie können überprüfen, ob Sie den [Control.InvokeRequired] (https://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired (v = vs.110) .aspx aufrufen müssen) Eigentum. – pstrjds