Как получить всю цепочку исключений в обработчике событий Application.ThreadException? - PullRequest
3 голосов
/ 14 сентября 2008

Я просто работал над исправлением обработки исключений в приложении .NET 2.0 и наткнулся на какую-то странную проблему с Application.ThreadException .

То, что я хочу - это иметь возможность отлавливать все исключения из событий за элементами GUI (например, button_Click и т. Д.). Затем я хочу отфильтровать эти исключения по «фатальности», например, с некоторыми типами исключений приложение должно продолжать работать, а с другими оно должно завершиться.

В другом приложении .NET 2.0 я узнал, что по умолчанию только в режиме отладки исключения фактически вызывают вызов Application.Run или Application.DoEvents. В режиме выпуска этого не происходит, и исключения должны быть «перехвачены» с помощью события Application.ThreadException.

Однако теперь я заметил, что объект исключения, передаваемый в ThreadExceptionEventArgs события Application.ThreadException, всегда является самым внутренним исключением в цепочке исключений . Для целей регистрации / отладки / проектирования я действительно хочу всю цепочку исключений, хотя. Нелегко определить, какая внешняя система вышла из строя, например, когда вы просто обрабатываете SocketException: когда он упакован как, например, исключение NpgsqlException, по крайней мере, вы знаете, что это проблема с базой данных.

Итак, как добраться до всей цепочки исключений из этого события? Возможно ли вообще или мне нужно спроектировать обработку исключений другим способом?

Обратите внимание, что у меня -сортировка есть обходной путь с использованием Application.SetUnhandledExceptionMode , но это далеко от идеала, потому что мне придется свернуть свой собственный цикл сообщений.

РЕДАКТИРОВАТЬ: чтобы предотвратить больше ошибок, метод GetBaseException () НЕ делает то, что я хочу : он просто возвращает самое внутреннее исключение, в то время как единственное, что у меня уже есть, это самое внутреннее исключение. Я хочу получить самое крайнее исключение!

Ответы [ 7 ]

3 голосов
/ 04 августа 2009
1 голос
/ 09 декабря 2009

Просто обнаружил что-то интересное. Различные события GUI принесут вам разные результаты. Исключение, выброшенное из обработчика события Form.Shown, приведет к тому, что Application.ThreadException перехватит самое внутреннее исключение, но точно такой же код, запущенный в событии Form.Load, приведет к получению исключения external-most пойман в Application.ThreadException.

1 голос
/ 21 ноября 2008

Обычно вы теряете всю цепочку исключений, кроме базового исключения в обработчике исключений Application.ThreadException, если исключение произошло в другом потоке.

Из библиотеки MSDN :

Это событие позволяет использовать Windows Forms. приложение для обработки в противном случае необработанные исключения, которые происходят в Windows Forms темы. Прикрепите ваш обработчики событий в ThreadException событие, чтобы справиться с этими исключениями, который оставит ваше заявление в неизвестное состояние. Где возможно, исключения должны обрабатываться блок обработки структурированных исключений.

Решение: Если вы выполняете многопоточность, убедитесь, что все ваши потоки / асинхронные вызовы находятся в блоке try / catch. Или, как вы сказали, вы можете играть с Application.SetUnhandledExceptionMode.

1 голос
/ 21 ноября 2008

Я пытался воспроизвести это поведение (всегда получая самое внутреннее исключение),
но я получаю ожидаемое исключение со всеми нетронутыми исключениями InnerException.

Вот код, который я использовал для проверки:

   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 обрабатывает Application.ThreadException. Сначала вызывается метод Test1 ().
Это результат (например, ThreadExceptionEventArgs), который я получаю в HandleAppException:

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

Если вы просто ловите и (пере) генерируете исключения, InnerExceptions не будет отображаться, но будет добавлен к исключению.

в SO.Test3 () в Test.vb: строка 166
в SO.Test2 () в Test.vb: строка 159
в SO.Test1 () в Test.vb: строка 151

0 голосов
/ 06 марта 2015

На основании некоторой информации в этой цепочке я использовал UnhandledExceptionMode.ThrowException, а не UnhandledExceptionMode.CatchException. Затем я ловлю исключение за пределами Run () формы, и это дает мне всю цепочку исключений.

0 голосов
/ 15 сентября 2008

Согласно документации MSDN:

При переопределении в производном классе возвращает исключение, являющееся основной причиной одного или нескольких последующих исключений.

    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

Вы можете использовать эту вариацию для анализа цепочки исключений.

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

Это показалось бы мне именно тем, что вы ищете.

0 голосов
/ 14 сентября 2008

Вы пробовали метод Exception.GetBaseException? Это возвращает исключение, которое создало Application.TreadException. Затем вы можете использовать тот же процесс, чтобы пройти по цепочке, чтобы получить все исключения.

исключение.getbaseexception Method

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...