Try/Catch on Application.Run работает в отладчике, но не работает при запуске самого приложения

Я сделал проект в VB.NET. Если приложение, которое я сделал, выдаст нежелательную ошибку, оно создаст текстовый файл, содержащий ошибку. Я смог сделать это при запуске в Visual Studio, но он не работает при запуске отдельного приложения, исполняемый файл находится в bin/Debug.

Вот что я сделал:

Sub Main(ByVal ParamArray args() As String)
  Try
System.Windows.Forms.Application.Run(New Form1)
  Catch ex As Exception
WriteErrorLogs(ex)
  End Try
End Sub

Sub WriteErrorLogs(Byval ex As Exception)
' create a textfile the write x.Message, x.Source, x.ToString
  Dim dnow As String = Now.ToString
  Dim filename As String = "Error " & removeInvalidChars(dnow)
  Dim saveto As String = New IO.FileInfo("Errors/" & filename).FullName & ".txt"
  Dim title As String = ex.Message
  Dim stacktrce As String = ex.StackTrace

  If Not IO.Directory.Exists(New IO.DirectoryInfo("Errors").FullName) Then IO.Directory.CreateDirectory("Errors")
  Dim fw As New IO.StreamWriter(saveto, False, System.Text.Encoding.UTF8)
  fw.WriteLine(title)
  fw.WriteLine()
  fw.WriteLine(stacktrce)
  fw.Close()
End Sub

Private Function removeInvalidChars(ByRef s As String)
  Dim invalidChars() As Char = "\/:*?""<>|".ToCharArray
  For Each i As Char In invalidChars
    s = s.Replace(i, ".")
  Next
  Return s
End Function

Есть ли лучшее решение для этого?

1 ответ

Решение
  Try
      System.Windows.Forms.Application.Run(New Form1)
  Catch ex As Exception
      WriteErrorLogs(ex)
  End Try

Да, это предложение Catch никогда не будет перехватывать исключение, когда вы запускаете его без подключенного отладчика. Исключения, которые возникают в потоке пользовательского интерфейса, перенаправляются и вместо этого вызывают событие Application.ThreadException. Который по умолчанию отображает диалоговое окно, вы должны были заметить, что когда вы запустили его из каталога bin\Debug.

Он работает по-другому, когда у вас подключен отладчик, этот диалог действительно мешает, когда вам нужно отлаживать необработанные исключения. Таким образом, событие ThreadException намеренно отключено, и отладчик показывает, где произошел сбой вашего кода. Что не произойдет с кодом, который вы написали, теперь, когда предложение Catch перехватывает исключение.

Предложение Catch также не будет работать, когда ваша программа потерпела крах из-за необработанного исключения, возникшего в рабочем потоке, она может видеть только исключения в потоке пользовательского интерфейса.

Вам потребуется более основательный подход, вы можете получить его из события AppDomain.UnhandledException. Который вызывается для любого необработанного исключения, независимо от того, в каком потоке оно было создано. Сделайте так, чтобы ваш код выглядел так:

Module Module1
    Public Sub Main(ByVal args() As String)
        Application.EnableVisualStyles()
        Application.SetCompatibleTextRenderingDefault(False)
        If Not System.Diagnostics.Debugger.IsAttached Then
            Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException)
            AddHandler AppDomain.CurrentDomain.UnhandledException, AddressOf LogUnhandledExceptions
        End If
        Application.Run(New Form1())
    End Sub

    Private Sub LogUnhandledExceptions(ByVal sender As Object, ByVal e As UnhandledExceptionEventArgs)
        Dim ex = DirectCast(e.ExceptionObject, Exception)
        '' Log or display ex.ToString()
        ''...
        Environment.Exit(System.Runtime.InteropServices.Marshal.GetHRForException(ex))
    End Sub
End Module

Использование Debugger.IsAttached гарантирует, что вы можете диагностировать необработанные исключения с помощью отладчика. Использование Application.SetUnhandledExceptionMode гарантирует, что диалоговое окно никогда не отображается и все исключения регистрируются.

Другие вопросы по тегам