2017-07-30 42 views
0

我第一次使用Sql Server Service Broker,試圖在特定表中發生更改時訂閱通知。我發現了以下情況例外,當我打電話command.ExecuteReader()使用SqlDependency無法接收更改通知

System.InvalidOperationException:當使用的SqlDependency沒有提供期權價值,SqlDependency.Start()之前,必須執行命令叫加入的SqlDependency實例。

我創建了一個測試,以重現的場景(留出一些對簡潔的相關方法),具體如下:

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

我發出下面的SQL查詢來嘗試更好地瞭解發生了什麼:

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 

有沒有人有任何想法,我可能做錯了什麼?

+0

是否https://stackoverflow.com/questions/19155819/error-when-using-sqldependency-without-providing-an-options-value help?或者https://stackoverflow.com/questions/27411100/sqldependency-startconnectionstring-return-every-time-false? – mjwills

+0

@mjwills第二個鏈接的答案有助於解決問題,即。使用帶選項參數的SqlDependency構造函數。如果您想發佈回覆而不是評論,我很樂意將其標記爲答案。謝謝! –

回答

0

錯誤消息說:

SqlDependency.Start()之前,必須執行命令叫加入的SqlDependency實例

上的幫助SqlDependency.Start狀態:

啓動監聽器接收依賴性更改通知。

...

確保啓動時才調用每個AppDomain

所以放置Start()呼叫某處您的應用程序的啓動。由於這看起來像一種測試方法,可能在[ClassInitialize]裝飾方法中。

+0

還有一點比這個還要多,但絕對問題的一部分是我每次調用SqlDependency.Start()時每個AppDomain不止一次 - 在我最初的情況下,我有兩個測試調用了同一個測試系統包含SqlDependency.Start()調用。 對於上面編寫的示例測試,我還必須使用帶有選項和超時的構造函數重載,並指定「SERVICE = [my-service-name]」選項來解決此問題。 –

+0

@remus小問題:SqlDependency.Start()在AppDomain啓動時調用它們。在SqlDependency.Start()之前調用SqlDependency.Stop()是否有意義? – Natalya

+0

@Natalya請問作爲一個單獨的問題 –