【问题标题】:Try/Catch on Application.Run works in debugger, but doesn't work when running the actual applicationTry/Catch on Application.Run 在调试器中工作,但在运行实际应用程序时不起作用
【发布时间】:2023-03-03 18:46:01
【问题描述】:

我在 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

有没有更好的解决方案?

【问题讨论】:

  • WriteErrorLogs 方法中的代码在哪里?
  • 不清楚您在这里寻求帮助的内容。您要写入的文件在哪里?是您无法写入文本文件的问题,还是更多关于错误处理最佳实践的查询?
  • 此外,还有很多方法可以处理日志记录。在this answer我详细说明了log4net
  • 您必须小心WriteErrorLogs 中的代码不会也抛出错误。例如,如果它试图写入 C:\ 驱动器的根目录,这可能会失败。
  • (已完成代码)我的问题是 Try Catch 错误陷阱在未处于调试模式时不起作用。假设 Form1 有一个调用错误的按钮。将在 Sub Main 上的 Catch 上引发错误。现在,我想知道是否有更好的解决方案,而不是使用 Try Catch 错误陷阱,因为它不适用于已部署的应用程序。

标签: .net vb.net error-handling


【解决方案1】:
  Try
      System.Windows.Forms.Application.Run(New Form1)
  Catch ex As Exception
      WriteErrorLogs(ex)
  End Try

是的,当您在没有附加调试器的情况下运行它时,该 Catch 子句永远不会捕获异常。在 UI 线程上引发的异常被 重新路由 并触发 Application.ThreadException 事件。默认情况下会显示一个对话框,您应该已经注意到,当您从 bin\Debug 目录运行它时。

当您连接了调试器时,它的工作方式会有所不同,当您需要调试未处理的异常时,该对话框确实会妨碍您。因此 ThreadException 事件被有意禁用,调试器会向您显示代码崩溃的位置。您编写的代码不会发生这种情况,因为 Catch 子句确实捕获了异常。

当您的程序由于工作线程上引发的未处理异常而崩溃时,Catch 子句也不起作用,它只能看到 UI 线程上的异常。

您将需要一种更可靠的方法,您可以从 AppDomain.UnhandledException 事件中获取一个。这是针对 any 未处理的异常引发的,无论它是在哪个线程上引发的。让你的代码看起来像这样:

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 可确保从不显示对话框并记录所有异常。

【讨论】:

  • 这正是我想要的。谢谢@Hans
  • +1 虽然这个答案在 VB.Net 中,但它对我很有帮助,因为它与我需要的 C# 实现几乎相同。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-29
  • 2021-04-09
  • 1970-01-01
  • 2019-05-10
相关资源
最近更新 更多