2017-07-30 8 views
0

Ich verwende Sql Server Service Broker zum ersten Mal und versuche, Benachrichtigungen zu abonnieren, wenn sich Änderungen in einer bestimmten Tabelle ergeben. Ich erhalte die folgende Ausnahme, wenn ich command.ExecuteReader() nennen:Ich kann keine Änderungsbenachrichtigungen über SqlDependency empfangen.

System.InvalidOperationException: Wenn SqlDependency verwenden, ohne einen Optionswert bereitstellt, SqlDependency.Start() muss die SqlDependency Instanz hinzugefügt vor der Ausführung eines Befehls aufgerufen werden .

Ich habe einen Test erstellt das Szenario (Weglassen einige der damit verbundenen Methoden der Kürze halber) zu reproduzieren, wie folgt:

private string _queueName = "EventsToPublishChangeMessages"; 
    private bool _notificationReceived; 

    [Test] 
    public void WhyDoesExceptionIndcateSqlDependencyStartHasNotBeenCalledPriorToCommandExecuteReader() 
    { 
     Console.WriteLine($"canRequestNotifications: {CanRequestNotifications()}"); // returns true 
     var connectionString = GetConnectionString(); 
     var started = SqlDependency.Start(connectionString, _queueName); // exception below seems to suggest that I haven't started the SqlDependency. Am I doing something wrong on this line? 
     Console.WriteLine($"Started:{started}"); // returns true 
     var connection = new SqlConnection(connectionString); 
     var command = new SqlCommand("SELECT Id, EventType, [Data], Created FROM dbo.EventsToPublish", connection); 
     var sqlDependency = new SqlDependency(command); 
     sqlDependency.OnChange += OnChange; 
     connection.Open(); 

     // The following line causes the exception: 
     // System.InvalidOperationException : When using SqlDependency without providing an options value, SqlDependency.Start() must be called prior to execution of a command added to the SqlDependency instance. 
     // But you can see that I *did* call SqlDependency.Start() above. 
     using (var reader = command.ExecuteReader()) 
     { 
      while (reader.Read()) 
      { 
       Process(reader); 
      } 
     } 

     TryToTriggerANotification(connectionString); 
     Thread.Sleep(5000); // ie. wait a few seconds to ensure notification-handling background thread has had a chance to complete. 

     Assert.That(_notificationReceived, Is.True); 
    } 

    private void TryToTriggerANotification(string connectionString) 
    { 
     using (var connection = new SqlConnection(connectionString)) 
     { 
      using (var command = new SqlCommand(
        "INSERT INTO dbo.EventsToPublish(Id, EventType, [Data], Created) VALUES(newid(), 'StackOverflowQuestionTest', '', GETDATE())", 
        connection)) 
      { 
       connection.Open(); 
       command.ExecuteNonQuery(); 
      } 
     } 
    } 

    private void OnChange(object sender, SqlNotificationEventArgs e) 
    { 
     _notificationReceived = true; 
    } 

    private bool CanRequestNotifications() 
    { 
     try 
     { 
      var sqlClientPermission = new SqlClientPermission(PermissionState.Unrestricted); 
      sqlClientPermission.Demand(); 
      return true; 
     } 
     catch 
     { 
      return false; 
     } 
    } 

ich die folgenden SQL-Abfragen ausgegeben haben, zu versuchen, ein besseres Verständnis von dem, was passiert:

select * from sys.service_queues -- can see my EventsToPublishChangeMessages queue 
select is_broker_enabled from sys.databases where database_id=db_id() -- returns 1 
select * from sys.dm_qn_subscriptions -- returns nothing 
select * from sys.transmission_queue -- returns nothing 

Hat jemand irgendwelche Ideen, was ich falsch machen könnte?

+0

Hilft https://stackoverflow.com/questions/19155819/error-when-using-sqldependency-without-providing-an- options-value? Oder https://stackoverflow.com/questions/27411100/sqldependency-startconnectionstring-return-every-time-false? – mjwills

+0

@mjwills Die Antwort in der zweiten Verbindung half, das Problem zu lösen, dh. Verwenden des SqlDependency-Konstruktors mit dem Optionsargument. Wenn Sie als Antwort anstelle eines Kommentars posten möchten, würde ich das gerne als Antwort markieren. Vielen Dank! –

Antwort

0

Die Fehlermeldung lautet:

SqlDependency.Start() müssen vor der Ausführung eines Befehls aufgerufen werden hinzugefügt, um die SqlDependency Instanz

Die Hilfe auf SqlDependency.Start heißt es:

der Starts Listener zum Empfangen von Benachrichtigungen über Abhängigkeitsänderungen.

...

Stellen Sie sicher, dass nur einmal starten AppDomain pro

genannt wird

So legen Sie einen Start() Anruf irgendwo in Ihrem App-Start. Da dies wie eine Testmethode aussieht, vielleicht in einer [ClassInitialize] dekorierten Methode.

+0

Es gab ein bisschen mehr als das, aber definitiv ein Teil des Problems war, dass ich SqlDependency.Start() mehr als einmal pro AppDomain aufgerufen hatte - in meinem ursprünglichen Fall hatte ich zwei Tests, die das gleiche System-unter-Test aufrufen das enthielt den Aufruf SqlDependency.Start(). Für den Beispieltest, der oben geschrieben wurde, musste ich auch die Konstruktorüberladung verwenden, die Optionen und Zeitüberschreitung annimmt, und Optionen von "SERVICE = [my-service-name]" angeben, um dieses Problem zu beheben. –

+0

@Remus Kleine Frage: SqlDependency.Start() ruft diejenigen beim Starten von AppDomain auf. Ist es sinnvoll, SqlDependency.Stop() vor SqlDependency.Start() aufzurufen? – Natalya

+0

@Natalya bitte fragen Sie als separate Frage –

Verwandte Themen