2016-05-25 25 views
10

Ho il codice seguente:Quando viene chiamato DbConnection.StateChange?

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

avvio il codice di cui sopra, mentre l'istanza del server SQL è in esecuzione. Procedere quindi ad eseguire

SHUTDOWN WITH NOWAIT; 

sull'istanza del server SQL a cui è connesso il programma. Quindi osservo l'arresto del servizio SQL server. Tuttavia, non vedo mai il messaggio "DB rilevato" nell'output. Perchè è questo?

A parte: Verrà richiamato il gestore di StateChange se poi tenterò di eseguire un'operazione sulla connessione SQL, ma mai in precedenza. C'è un modo in cui questo comportamento può essere cambiato?

+0

"Verrà richiamato il gestore StateChange se tenterò di eseguire un'operazione sulla connessione SQL" - In realtà rispondi alla domanda. L'oggetto Connection non esegue il ping del server e controlla lo stato solo quando necessario. Metti 'connection.Open()' dopo '.StateChange + = ...' per vedere che funziona. –

+0

@AlexKudryashev Non dovrebbe esserci qualche tipo di keep alive tra il client SQL e il server SQL? La mia comprensione è che gli oggetti SqlConnection dovrebbero mappare le sessioni one-to-one al server SQL. Se il server uccide la sessione, c'è un modo in cui posso far passare tali informazioni al mio codice? –

+0

si potrebbe provare a eseguire il polling del server con qualcosa di innocuo come 'selezionare 1' –

risposta

3

L'evento StateChange è destinato allo stato della connessione, non all'istanza del server del database. Per ottenere lo stato del server di database,

L'evento StateChange si verifica quando lo stato dei cambiamenti degli eventi da chiuso a aperto o aperto al chiuso.

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

Se avete intenzione di rotolare il proprio monitor per il database, allora si può considerare l'utilizzo di un metodo che restituisce vero/falso se la connessione è disponibile e ping che metodo su un programma. Potresti anche avvolgere un metodo per farlo in un ciclo infinito ripetendolo dopo un certo periodo di tempo e alzare il proprio evento quando questo "stato" cambia davvero.

Ecco un metodo rapido di un altro SO risposta che è un approccio semplice:

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

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

+0

"L'evento StateChange è destinato allo stato della connessione, non all'istanza del server di database." -> Ma se lo stato del server cambia, allora anche lo stato della connessione dovrebbe cambiare (cioè diventare "non più funzionante"). –

+0

Ma la connessione non rileverà la modifica dello stato del server di database a meno che non si investa effettivamente qualcosa contro il server, ecco perché dovresti avere un wrapper come indicato nella risposta, in modo da avere un modo affidabile per identificare le vere modifiche dello stato e non solo a livello di applicazione. –

8

Quando viene chiamato DbConnection.StateChange?

È possibile trovare il codice sorgente di riferimento Microsoft.

L'evento StateChange viene generato dalla funzione DbConnection.OnStateChange. La ricerca di riferimenti a questa funzione fornisce solo alcune istanze:

In primo luogo, nella classe SqlConnection, OnStateChange viene chiamato solo nel metodo Close.

Quindi nel file DbConnectionHelper.cs, c'è una classe parziale denominata DBCONNECTIONOBJECT. Sembra che sia stato utilizzato per tutte le classi precedenti allo DbConnection utilizzando alcuni shenanigans build-time. Quindi puoi considerarlo come parte di SqlConnection. In ogni caso, chiama OnStateChange solo all'interno della funzione SetInnerConnectionEvent.

Per quello che posso dire (il nonsense di classe parziale lo rende difficile), lo SqlConnection.SetInnerConnectionEvent viene chiamato solo da .E che si chiama da:

Così, in sintesi - l'evento viene generato solo in risposta ad azioni sul lato client - non ci fa sembra essere un polling dello stato della connessione integrato in SQLConnection.

C'è un modo in cui questo comportamento può essere modificato?

Guardando il codice sorgente, non riesco a vederne uno. Come altri hanno suggerito, potresti implementare il tuo sondaggio, ovviamente.