Come ottenere l'intera catena di eccezioni nel gestore eventi Application.ThreadException?

StackOverflow https://stackoverflow.com/questions/61354

  •  09-06-2019
  •  | 
  •  

Domanda

Stavo lavorando per sistemare la gestione delle eccezioni in un'app .NET 2.0 e mi sono imbattuto in uno strano problema con Application.ThreadException.

Quello che voglio è essere in grado di catturare tutte le eccezioni dagli eventi dietro gli elementi della GUI (ad es.pulsante_clic, ecc.).Voglio quindi filtrare queste eccezioni in base alla "fatalità", ad es.con alcuni tipi di eccezioni l'applicazione dovrebbe continuare a funzionare e con altri dovrebbe uscire.

In un'altra app .NET 2.0 ho appreso che, per impostazione predefinita, solo in modalità debug le eccezioni lasciano effettivamente una chiamata Application.Run o Application.DoEvents.Nella modalità di rilascio ciò non accade e le eccezioni devono essere "catturate" utilizzando l'evento Application.ThreadException.

Ora, però, l'ho notato l'oggetto eccezione passato nel ThreadExceptionEventArgs dell'evento Application.ThreadException è sempre l'eccezione più interna nella catena di eccezioni.Per scopi di registrazione/debug/progettazione, però, voglio davvero l'intera catena di eccezioni.Non è facile determinare quale sistema esterno ha fallito, ad esempio quando riesci a gestire una SocketException:quando è avvolto come ad es.una NpgsqlException, almeno sai che è un problema del database.

Quindi, come arrivare all'intera catena di eccezioni di questo evento? È possibile o devo progettare la gestione delle eccezioni in un altro modo?

Nota che, in un certo senso, ho un soluzione alternativa utilizzando Application.SetUnhandledExceptionMode, ma questo è tutt'altro che ideale perché dovrei eseguire il mio ciclo di messaggi.

MODIFICARE:per evitare ulteriori errori, il metodo GetBaseException() NON fa quello che voglio:restituisce semplicemente l'eccezione più interna, mentre l'unica cosa che ho già è l'eccezione più interna.Voglio arrivare all'eccezione più esterna!

È stato utile?

Soluzione

Questa domanda è formulata in modo più utile e ha ricevuto risposta qui:

Perché l'eccezione interna raggiunge il gestore ThreadException e non l'effettiva eccezione generata?

Altri suggerimenti

Ho provato a riprodurre questo comportamento (ottenendo sempre l'eccezione più interna),
ma ottengo l'eccezione che mi aspetto, con tutte le InnerException intatte.

Ecco il codice che ho usato per testare:

   Private Shared Sub Test1()
      Try
         Test2()
      Catch ex As Exception
         Application.OnThreadException(New ApplicationException("test1", ex))
      End Try
   End Sub

   Private Shared Sub Test2()
      Try
         Test3()
      Catch ex As Exception
         Throw New ApplicationException("test2", ex)
      End Try
   End Sub

   Private Shared Sub Test3()
      Throw New ApplicationException("blabla")
   End Sub

Private Shared Sub HandleAppException(ByVal sender As Object, ByVal e As ThreadExceptionEventArgs)
...
End Sub

Sub HandleAppException gestisce Application.ThreadException.Il metodo Test1() viene chiamato per primo.
Questo è il risultato (e As ThreadExceptionEventArgs) che ottengo in HandleAppException:

ThreadException http://mediasensation.be/dump/?download=ThreadException.jpg

Se catturi e (ri)lanci semplicemente eccezioni, non verrà visualizzata alcuna InnerException, ma verrà aggiunta all'eccezione.StackTrace, come questo:

in SO.Test3() in Test.vb:riga 166
in SO.Test2() in Test.vb:riga 159
in SO.Test1() in Test.vb:riga 151

Normalmente, si perde l'intera catena di eccezioni ad eccezione dell'eccezione di base in un gestore di eccezioni Application.ThreadException se l'eccezione si è verificata in un altro thread.

Dal Libreria MSDN:

Questo evento consente all'applicazione di Windows di gestire eccezioni altrimenti non gestite che si verificano Moduli Windows discussioni.Allega i gestori di eventi all'evento ThreadException per affrontare queste eccezioni, che lascerà la tua domanda in uno stato sconosciuto.Ove possibile, le eccezioni dovrebbero essere gestite da un blocco di gestione delle eccezioni strutturate.

Soluzione:Se esegui il threading, assicurati che tutti i thread/chiamate asincrone siano in un blocco try/catch.O come hai detto, puoi giocare con Application.SetUnhandledExceptionMode.

Ho appena scoperto qualcosa di interessante.Diversi eventi della GUI ti daranno risultati diversi.Un'eccezione generata da un gestore eventi Form.Shown comporterà che Application.ThreadException catturi l'eccezione più interna, ma lo stesso identico codice eseguito nell'evento Form.Load comporterà l'errore più esterno eccezione che viene catturata in Application.ThreadException.

Hai provato il metodo Exception.GetBaseException?Ciò restituisce l'eccezione che ha creato Application.TreadException.Potresti quindi utilizzare lo stesso processo per risalire la catena per ottenere tutte le eccezioni.

Metodo eccezione.getbaseexception

Sulla base di alcune informazioni in questa catena, ho utilizzato UnhandledExceptionMode.ThrowException anziché UnhandledExceptionMode.CatchException.Quindi catturo l'eccezione all'esterno di Run() del modulo e questo mi fornisce l'intera catena di eccezioni.

Secondo la documentazione MSDN:

Quando sottoposto a override in una classe derivata, restituisce l'eccezione che è la causa principale di una o più eccezioni successive.

    Public Overridable Function GetBaseException() As Exception
        Dim innerException As Exception = Me.InnerException
        Dim exception2 As Exception = Me
        Do While (Not innerException Is Nothing)
            exception2 = innerException
            innerException = innerException.InnerException
        Loop
        Return exception2
    End Function

Potresti usare una variazione su questo per analizzare la catena di eccezioni.

Public Sub LogExceptionChain(ByVal CurrentException As Exception)

    Dim innerException As Exception = CurrentException.InnerException
    Dim exception2 As Exception = CurrentException

    Debug.Print(exception2.Message) 'Log the Exception

    Do While (Not innerException Is Nothing)

        exception2 = innerException
        Debug.Print(exception2.Message) 'Log the Exception

        'Move to the next exception
        innerException = innerException.InnerException
    Loop

End Sub

Questo mi sembrerebbe esattamente quello che stai cercando.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top