Как получить всю цепочку исключений в обработчике событий Application.ThreadException?

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

  •  09-06-2019
  •  | 
  •  

Вопрос

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

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

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

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

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

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

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

Это было полезно?

Другие советы

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

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

   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().
Это результат (e As 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

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

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

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

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

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

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

Метод исключения.getbaseException

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

Согласно документации 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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top