Comment obtenir toute la chaîne d'exceptions dans le gestionnaire d'événements Application.ThreadException ?

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

  •  09-06-2019
  •  | 
  •  

Question

Je travaillais justement sur la gestion des exceptions dans une application .NET 2.0 et je suis tombé sur un problème étrange avec Application.ThreadException.

Ce que je veux, c'est pouvoir détecter toutes les exceptions des événements derrière les éléments de l'interface graphique (par ex.bouton_Clic, etc.).Je souhaite ensuite filtrer ces exceptions sur la « fatalité », par ex.avec certains types d'exceptions, l'application doit continuer à fonctionner et avec d'autres, elle doit se fermer.

Dans une autre application .NET 2.0, j'ai appris que, par défaut, uniquement en mode débogage, les exceptions laissent réellement un appel Application.Run ou Application.DoEvents.En mode release, cela ne se produit pas et les exceptions doivent être « interceptées » à l'aide de l'événement Application.ThreadException.

Mais maintenant, j'ai remarqué que l'objet d'exception transmis dans ThreadExceptionEventArgs de l'événement Application.ThreadException est toujours l'exception la plus interne de la chaîne d'exceptions.À des fins de journalisation/débogage/conception, je veux vraiment toute la chaîne d'exceptions.Il n'est pas facile de déterminer quel système externe a échoué, par exemple lorsque vous gérez simplement une SocketException :quand il est enveloppé comme par ex.une NpgsqlException, alors au moins vous savez que c'est un problème de base de données.

Alors, comment accéder à toute la chaîne des exceptions à cet événement ? Est-ce même possible ou dois-je concevoir ma gestion des exceptions d'une autre manière ?

Notez que j'ai en quelque sorte un solution de contournement en utilisant Application.SetUnhandledExceptionMode, mais c'est loin d'être idéal car je devrais lancer ma propre boucle de messages.

MODIFIER:pour éviter plus d'erreurs, la méthode GetBaseException() ne fait PAS ce que je veux:il renvoie simplement l'exception la plus interne, alors que la seule chose que j'ai déjà est l'exception la plus interne.Je veux arriver à l'exception la plus extrême !

Était-ce utile?

La solution

Autres conseils

J'ai essayé de reproduire ce comportement (en obtenant toujours l'exception la plus interne),
mais j'obtiens l'exception à laquelle je m'attends, avec toutes les InnerExceptions intactes.

Voici le code que j'ai utilisé pour tester :

   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

Le sous HandleAppException gère Application.ThreadException.La méthode Test1() est appelée en premier.
Voici le résultat (e As ThreadExceptionEventArgs) que j'obtiens dans HandleAppException :

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

Si vous capturez et (re)lancez simplement des exceptions, aucune InnerException n'apparaîtra, mais elle sera ajoutée à l'exception.Trace de la pile, comme ça:

à SO.Test3() dans Test.vb:ligne 166
à SO.Test2() dans Test.vb:ligne 159
à SO.Test1() dans Test.vb:ligne 151

Normalement, vous ne perdez toute la chaîne d'exceptions, à l'exception de l'exception de base dans un gestionnaire d'exceptions Application.ThreadException, que si l'exception s'est produite dans un autre thread.

Du Bibliothèque MSDN:

Cet événement permet à votre application Windows Forms de gérer des exceptions autrement non perdues qui se produisent dans Formulaires Windows fils.Ajoutez vos gestionnaires d'événements à l'événement ThreadException pour gérer ces exceptions, qui laisseront votre application dans un état inconnu.Dans la mesure du possible, les exceptions doivent être gérées par un bloc de gestion des exceptions structuré.

Solution:Si vous effectuez du threading, assurez-vous que tous vos threads/appels asynchrones sont dans un bloc try/catch.Ou comme vous l'avez dit, vous pouvez jouer avec Application.SetUnhandledExceptionMode.

Je viens de découvrir quelque chose d'intéressant.Différents événements GUI vous donneront des résultats différents.Une exception levée à partir d'un gestionnaire d'événements Form.Shown entraînera Application.ThreadException à intercepter l'exception la plus interne, mais exactement le même code exécuté dans l'événement Form.Load entraînera le le plus à l'extérieur exception interceptée dans Application.ThreadException.

Avez-vous essayé la méthode Exception.GetBaseException ?Cela renvoie l'exception qui a créé Application.TreadException.Vous pouvez ensuite utiliser le même processus pour remonter la chaîne afin d'obtenir toutes les exceptions.

Méthode exception.getbaseexception

Sur la base de certaines informations de cette chaîne, j'ai utilisé UnhandledExceptionMode.ThrowException par opposition à UnhandledExceptionMode.CatchException.J'attrape ensuite l'exception en dehors de Run() du formulaire et cela me donne toute la chaîne d'exceptions.

D'après la documentation MSDN :

En cas de substitution dans une classe dérivée, renvoie l'exception qui est à l'origine d'une ou plusieurs exceptions ultérieures.

    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

Vous pouvez utiliser une variante pour analyser la chaîne d'exceptions.

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

Cela me semblerait être exactement ce que vous recherchez.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top