.net 我可以在C#中创建一个全局异常处理程序,让代码在以后继续运行吗?

mepcadol  于 2022-11-19  发布在  .NET
关注(0)|答案(8)|浏览(333)

在.NET中,默认的异常处理程序将允许用户继续运行程序。但是,我希望有一个全局异常处理程序,它将堆栈跟踪保存到一个“errorlog.txt”文件中,这样用户就可以将其发送给我,而不必记住单击“Details”并将其复制到对话框之外(并删除所有关于加载的程序集等无用的废话)。但当我这样做时,代码不知道如何继续,所以我所能做的就是退出应用程序。有没有办法两全其美?(是的,我知道我所要求的本质上是“On Error Resume Next”(错误恢复下一个),但我真的认为它会很有用!)

nwnhqdif

nwnhqdif1#

AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

如果在应用程序启动时将自己绑定到该事件,则应该能够捕获应用程序引发的任何未处理异常,并将其保存到文件中。(使用UnhandledExceptionEventArgsException对象部分。我认为不可能从错误发生的位置恢复。

7kjnsjlb

7kjnsjlb2#

你可以编写一个全局异常处理方法,在每个catch块中调用,它将堆栈跟踪写到你想保存它的任何地方。但是你需要为每个需要它们的操作编写try . . . catch块,并在每个块中调用异常处理。
你也可以在MyApplication.UnhandledException处理程序中调用全局异常处理方法来处理所有未处理的事件,但是在这种情况下,当控制权到达该方法时,程序将不会继续运行。

mzsu5hc0

mzsu5hc03#

不存在,异常是一个流控制构造,所以On Error Resume Next是不可能的。
您可以在循环中执行操作,并在出现异常时重试您的逻辑。
然而,KandallFrey是对的,你不应该使用异常作为流控制,只在异常情况下使用它们。

wmomyfyw

wmomyfyw4#

在Winform应用程序中,你可以为Application.ThreadException事件附加一个处理程序(确保在调用Application.Run()之前这样做)。这将摆脱标准的异常对话框(带有“details”按钮的对话框),并给予你能够显示/记录任何你想要的内容。
但是,请记住,这只适用于UI线程中引发的异常。从后台线程引发的异常将无法从您的处理程序访问。但是,这些异常仍然可以被AppDomain.UnhandledException处理程序捕获。

bybem2ql

bybem2ql5#

在主构造函数中,放置以下内容,并将全局执行:

AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) =>
{
   MessageBox.Show(eventArgs.Exception.ToString());
};
2mbi3lxu

2mbi3lxu6#

我使用My.Application.UnhandledException打开一个对话框窗体,用户可以在其中保存有关异常的所有信息。
当窗体关闭时,我调用e.ExitApplication = False

8oomwypt

8oomwypt7#

在我的公司,我已经建立了一个异常处理框架,它已经为我服务了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

当在Method2()中第一次调用Throw BSExceptionHandler.GetBSException(ex, BSExceptionHandler.GetThisMethodName)时,原始异常被 Package 在BSException中,并且原始方法名也被存储(稍后将详细介绍)。任何对BSExceptionHandler.GetBSException(ex, BSExceptionHandler.GetThisMethodName)的后续调用(例如在Method1()中)都将识别出该异常已经是BSException类型,并抛出该异常而不是重新 Package 它。最终,它到达调用堆栈的“顶部”(不是真正的顶部,只是我决定通过框架处理异常的点--即记录异常、通知用户等)--在本例中,在Button1_Click中--然后调用BSExceptionHandler.ProcessException(BSExceptionHandler.GetBSException(ex, BSExceptionHandler.GetThisMethodName))
我的框架在ProcessException中所做的是确定系统上配置的报告类型。这默认为“simple”,这意味着用户会得到一个非常通用的、侵入性最小的对话框,指示出现了问题,并指示他们联系IT部门。然而,这里有一个可选的注册表设置,可以将报告类型设置为“详细”或“电子邮件,”我在开发机器上使用“详细,”因为它包含了对话框中的所有异常信息,所以我不必查看日志。“email”选项用于在没有用户登录的情况下运行应用程序的服务器;在这种情况下,错误信息将通过电子邮件发送给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块,然后在catch中键入代码片段的快捷方式--例如“pbs”或“tbs”--块并按Tab键填充相应的异常处理方法。因此,在每种方法中使用这个框架都非常简单。我甚至修改了我的VS项目模板,使其始终引用并包含该框架,这样我就不会在你不必为每个新项目都这样做。
因此,关于GetThisMethodName()函数:此方法使用System.Diagnostics.StackTraceSystem.Diagnostics.StackFrameSystem.Reflection.MethodBase来确定BSException中 Package 了原始异常的方法的名称。

zy1mlcev

zy1mlcev8#

对我来说,这个解决方案:
1.在WebApiConfig.cs中添加:

public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.Services.Replace(typeof(IExceptionLogger), new UnhandledExceptionLogger());
            ...
        }

1.创建新文件UnhandledExceptionLogger.cs:

public class UnhandledExceptionLogger : ExceptionLogger
    {
        public override void Log(ExceptionLoggerContext context)
        {
            File.AppendAllText("log.txt", context.Exception.ToString());
        }
    }

相关问题