2016-05-25 41 views
10

Ich habe den folgenden Code:Wann wird DbConnection.StateChange aufgerufen?

class Program 
{ 
    static void Main() 
    { 
     var connection = new SqlConnection("myConnectionString"); 
     connection.Open(); 
     connection.StateChange += HandleSqlConnectionDrop; 
     Console.WriteLine("Hi"); 
     Console.ReadLine(); 
    } 

    private static void HandleSqlConnectionDrop(object connection, StateChangeEventArgs args) 
    { 
     Console.WriteLine("DB change detected"); 
    } 
} 

ich den obigen Code zu starten, während die SQL-Server-Instanz ausgeführt wird. Ich gehe dann

SHUTDOWN WITH NOWAIT; 

auf der SQL-Serverinstanz auszuführen, die das Programm verbunden ist. Ich beobachte dann den SQL-Serverdienst, der anhält. Ich sehe jedoch nie die Meldung "DB change detected" in der Ausgabe. Warum ist das?

Beiseite: Ich werde sehen, dass der StateChange-Handler aufgerufen wird, wenn ich dann versuche, eine Operation auf der SQL-Verbindung durchzuführen, aber nie zuvor. Gibt es eine Möglichkeit, dieses Verhalten zu ändern?

+0

"Ich werde sehen, dass der StateChange-Handler aufgerufen wird, wenn ich dann versuche, eine Operation auf der SQL-Verbindung durchzuführen" - Tatsächlich beantworten Sie Ihre Frage. Das Verbindungsobjekt pingt den Server nicht und überprüft den Status nur bei Bedarf. Platziere 'connection.Open()' nach '.StateChange + = ...' um zu sehen, dass es funktioniert. –

+0

@AlexKudryashev Sollte zwischen dem SQL-Client und dem SQL-Server nicht eine Art von Keep am Leben bleiben? Nach meinem Verständnis sollten SqlConnection-Objekte Eins-zu-eins-SQL-Server-Sitzungen zugeordnet werden. Wenn der Server die Sitzung beendet, kann ich diese Informationen an meinen Code weitergeben? –

+0

Sie könnten versuchen, den Server mit etwas harmlos wie 'Select 1' abzufragen. –

Antwort

3

Das Ereignis StateChange ist für den Status der Verbindung bestimmt, nicht für die Instanz des Datenbankservers. Um den Status des Datenbankservers zu erhalten,

Das Statechange-Ereignis tritt auf, wenn sich der Zustand des Ereignisses ändert sich von geöffnet geschlossen oder geschlossene geöffnet.

Von MSDN: https://msdn.microsoft.com/en-us/library/system.data.common.dbconnection.statechange(v=vs.110).aspx

Wenn Sie Ihren eigenen Monitor für die Datenbank rollen gehen, dann können Sie eine Methode in Betracht ziehen, die wahr/falsch zurück, wenn die Verbindung über verfügbare und Ping, das Verfahren ist ein Zeitplan. Sie können sogar eine Methode umwandeln, um dies in einer Endlosschleife zu tun, die sich nach einer gewissen Zeit wiederholt und ihr eigenes Ereignis auslöst, wenn sich dieser "Zustand" dann wirklich ändert.

Hier ist eine schnelle Methode von einem anderen SO beantworten, dass ein einfacher Ansatz:

/// <summary> 
/// Test that the server is connected 
/// </summary> 
/// <param name="connectionString">The connection string</param> 
/// <returns>true if the connection is opened</returns> 
private static bool IsServerConnected(string connectionString) 
{ 
    using (SqlConnection connection = new SqlConnection(connectionString)) 
    { 
     try 
     { 
      connection.Open(); 
      return true; 
     } 
     catch (SqlException) 
     { 
      return false; 
     } 
    } 
} 

Quelle: https://stackoverflow.com/a/9943871/4154421

+0

"Das StateChange-Ereignis ist für den Status der Verbindung bestimmt, nicht für die Instanz des Datenbankservers." -> Aber wenn sich der Zustand des Servers ändert, sollte sich auch der Zustand der Verbindung ändern (dh "nicht mehr funktionstüchtig" werden). –

+0

Die Verbindung wird jedoch die Zustandsänderung des Datenbankservers nicht erkennen, wenn Sie tatsächlich etwas abfragen gegen den Server, weshalb Sie einen Wrapper wie in der Antwort angegeben haben sollten, damit Sie die wahren Statusänderungen zuverlässig erkennen können und nicht nur auf Ihrer Anwendungsebene. –

8

Wenn DbConnection.StateChange genannt?

Sie können herausfinden, indem Sie sich den Microsoft Referenzquellcode ansehen.

Das Ereignis StateChange wird durch die Funktion DbConnection.OnStateChange ausgelöst. Suchen Sie nach Referenzen zu dieser Funktion ergibt sich nur ein paar Beispiele:

Zum einen in der SqlConnection Klasse wird OnStateChange nur in der Close Methode aufgerufen.

Dann in der DbConnectionHelper.cs Datei, gibt es eine partielle Klasse DBCONNECTIONOBJECT genannt. Es sieht so aus, als ob es für alle DbConnection-abgeleiteten Klassen mit einigen Build-Time-Shenanigans verwendet wird. Sie können es als Teil von SqlConnection betrachten. In jedem Fall ruft es OnStateChange nur aus der SetInnerConnectionEvent Funktion.

Soweit ich das beurteilen kann (der teilweise Klassenunsinn macht es schwierig), wird der SqlConnection.SetInnerConnectionEvent nur von SqlConnectionFactory.SetInnerConnectionEvent angerufen.Und dass von genannt:

So in der Zusammenfassung - das Ereignis nur als Reaktion auf die clientseitige Aktionen ausgelöst wird - es tut nicht scheinen alle Abfragen des Verbindungsstatus zu sein, der in SQLConnection eingebaut ist.

Gibt es eine Möglichkeit, dieses Verhalten zu ändern?

Mit Blick auf den Quellcode kann ich keinen sehen. Wie andere vorgeschlagen haben, könnten Sie natürlich Ihre eigenen Abfragen durchführen.

Verwandte Themen