在.NET中,默认的异常处理程序将让用户继续运行该程序。但是,我希望有一个全局异常处理程序将堆栈跟踪保存到“errorlog.txt”文件,以便用户可以将其发送给我,而不必记住单击“详细信息”并将其复制出来对话框(并删除所有关于加载的程序集等无用的废话)。但是当我这样做时,代码不知道如何继续,所以我所能做的就是退出应用程序。有没有办法让两全其美? (是的,我知道我要求的是基本上是“On Error Resume Next”的日志记录,但我认为它会很有用!)
答案 0 :(得分:24)
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
如果您在应用程序启动时将自己绑定到此事件,则应该能够捕获应用程序抛出的任何未处理异常,并将其保存到文件中。 (使用Exception
的{{1}}对象部分。我不相信可以从错误发生的地方恢复。
答案 1 :(得分:2)
不存在,例外是流控制构造,因此On Error Resume Next
是不可能的。
您可以在循环和异常中执行操作,重试逻辑。
KandallFrey是正确的,但是你不应该使用异常作为流量控制,只在特殊情况下使用它们。
答案 2 :(得分:2)
您可以编写一个全局异常处理程序方法,在每个catch
块中调用该方法,该方法将堆栈跟踪写入您想要保存的位置。但是你需要为每个需要它们的操作编写try . . . catch
块,并在每个块中调用异常处理程序。
您还可以在MyApplication.UnhandledException
处理程序中为所有未处理的事件调用该全局异常处理程序方法。但是当在这种情况下控制进入该方法时,程序将不会继续运行。
答案 3 :(得分:0)
我使用My.Application.UnhandledException
打开一个对话框,用户可以在其中保存有关异常的所有信息。
表单关闭后,我致电e.ExitApplication = False
。
答案 4 :(得分:0)
在Winform应用程序中,您可以将处理程序附加到Application.ThreadException
事件(确保在调用Application.Run()
之前执行此操作)。这将摆脱标准异常对话框(具有"详细信息"按钮的对话框),并使您能够显示/记录您想要的任何内容。
但是,请记住,这只适用于仅适用于在UI线程中抛出的异常。从后台线程引发的异常无法从您的处理程序访问。但是,AppDomain.UnhandledException
处理程序仍然可以捕获它们。
答案 5 :(得分:0)
在主构造函数中,将其放到全局范围内:
AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) =>
{
MessageBox.Show(eventArgs.Exception.ToString());
};
答案 6 :(得分:-1)
在我的公司,我已经建立了一个异常处理框架,这个框架已经为我服务了7年了。每个程序集都引用DLL,每个程序集中的每个方法都有一个try-catch块。在catch中,我基本上必须根据“我希望我的异常处理框架在哪里进行干预,即在外部记录异常数据并告知用户问题?”这一问题做出一个决定。在大多数情况下,这个问题的答案是我希望它在外部调用方法的情况下进行干预,例如:如果它在事件处理程序或其他委托中。所以这里有一些示例代码:
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Try
Method1()
Catch ex As Exception
BSExceptionHandler.ProcessException(BSExceptionHandler.GetBSException(ex, BSExceptionHandler.GetThisMethodName))
End Try
End Sub
Private Sub Method1()
Try
method2()
Catch ex As Exception
Throw BSExceptionHandler.GetBSException(ex, BSExceptionHandler.GetThisMethodName)
End Try
End Sub
Private Sub method2()
Try
Dim x As Integer = CInt("x") 'exception thrown here.
Catch ex As Exception
Throw BSExceptionHandler.GetBSException(ex, BSExceptionHandler.GetThisMethodName)
End Try
End Sub
首次在Throw BSExceptionHandler.GetBSException(ex, BSExceptionHandler.GetThisMethodName)
中调用Method2()
时,原始异常将包含在BSException
内,并且还会存储原始方法名称(稍后会详细介绍) 。随后对BSExceptionHandler.GetBSException(ex, BSExceptionHandler.GetThisMethodName)
的任何来电,例如在Method1()
中,将识别该异常已经是BSException
类型并且只是抛出它而不是重新包装它。最终,它达到调用堆栈的“顶部”(不是真正的顶层,只是我决定通过我的框架处理异常的点 - 即记录它,通知用户等) - - 在这种情况下,在Button1_Click
- 然后调用BSExceptionHandler.ProcessException(BSExceptionHandler.GetBSException(ex, BSExceptionHandler.GetThisMethodName))
。
我的框架在ProcessException
中的作用是确定系统上配置的报告类型。这被默认为“简单”,这意味着用户获得一个非常通用且极少侵入的对话框,指示已发生问题并指示他们联系IT部门。但是,有一个可选的注册表设置,它将报告类型设置为“详细”或“电子邮件”。我在我的开发机器上使用“verbose”,因为它包含对话框中的所有异常信息,所以我不必去查看日志。 “电子邮件”选项用于我没有用户登录时运行应用程序的服务器;在这种情况下,错误信息将通过电子邮件发送给IT部门,以提醒他们注意问题。
从此处发生的另一件事,无论报告类型如何,都将错误信息记录到Windows事件日志中。这是一个例子:
SILENT: No
ROOT ASSEMBLY: C:\Users\roryap\AppData\Local\Temporary Projects\WindowsApplication1\bin\Debug\WindowsApplication1.exe
DESCRIPTION: BromsunExceptionHandling.BSException: Calling Method 'WindowsApplication1.Form1.method2()' produced 'System.FormatException' exception with message 'Conversion from string "x" to type 'Integer' is not valid.'.
CALLING METHOD: WindowsApplication1.Form1.method2()
STACK TRACE: at Microsoft.VisualBasic.CompilerServices.Conversions.ToInteger(String Value)
at WindowsApplication1.Form1.method2() in C:\Users\roryap\AppData\Local\Temporary Projects\WindowsApplication1\Form1.vb:line 32
CALL STACK: WindowsApplication1.Form1.method2()
WindowsApplication1.Form1.Method1()
WindowsApplication1.Form1.Button1_Click(sender As System.Object, e As System.EventArgs)
SOURCE: Microsoft.VisualBasic
TARGET SITE: Int32 ToInteger(System.String)
EXTRA INFO:
当用户向IT报告问题时,IT所要做的就是检查他们的事件日志以获取错误信息。此外,申请不退出;它继续运行因为它永远不允许异常在您选择使用处理框架处理异常的点之外冒泡。一旦它被框架处理,它就完成了。
虽然这种方法有一些缺点,但我发现它是一个非常强大的系统,多年来它为我节省了许多小时的盲目故障排除。我创建了片段,所以我要做的就是创建一个try-catch块,然后输入片段快捷方式 - 例如“pbs”或“tbs” - 进入catch-block并点击tab键以填充相应的异常处理方法。因此,在每种方法中使用此框架都非常轻松。我甚至修改了我的VS项目模板,以便始终引用并包含框架,因此我不必为每个新项目都这样做。
因此,关于GetThisMethodName()
函数:此方法使用System.Diagnostics.StackTrace
,System.Diagnostics.StackFrame
和System.Reflection.MethodBase
来确定原始异常包含在其中的方法的名称BSException。