未处理的异常被吞掉了(除了调试器)

4
我正在维护一款使用.NET 4.0框架的遗留C# Winform应用程序。该应用程序工作良好,但偶尔由于应用程序中的错误,在应用程序创建无效数据时应用程序将无法正常工作。
在某些点上,我们将(无效/损坏)数据绑定到datagrid,当它试图将空列映射到datagrid列时,会导致许多错误。
其中包括异常类型为“System.InvalidCastException”的异常在mscorlib.dll中发生,但未在用户代码中处理,以及附加信息:“对象无法从DBNull转换为其他类型。”
以及
异常类型为“System.Reflection.TargetInvocationException”的异常在System.Windows.Forms.dll中发生,但未在用户代码中处理。
这些错误会在Visual Studio调试器下运行时显示一个漂亮的弹出窗口,详细说明错误,并允许我查看错误发生的行。
在这种特殊情况下,我知道问题所在,因此可以轻松地进行更正。然而,这种错误类别在应用程序的其他部分经常发生,因此不总是很明显发生了什么,而且我的用户并不总是提供良好的错误报告。为了解决这个问题,我想向应用程序添加日志记录(使用log4net),在我们的情况下可以这样做,因为每个用户都有自己的应用程序副本,所以我可以在事后获取每个用户的日志。
使用stackoverflow以及其他各种来源的提示,我找到了许多有关设置这些未处理异常处理程序的良好信息。不幸的是,我的处理程序对大多数“未处理”异常都没有被调用。
以下是应用程序的大部分相关部分:
static class Program {
    private static readonly ILog log = LogManager.GetLogger("Main");

    static void Main() {
        // Add some error handlers which log error data to the logfile
        //
        // For UI events (set the unhandled exception mode to force all Windows Forms
        // errors to go through our handler)
        Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
        Application.ThreadException += new ThreadExceptionEventHandler(delegate(object s, ThreadExceptionEventArgs e) {
            ExceptionLogger(e.Exception);
        });
        // Non-UI thread exceptions
        AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(delegate(object sender, UnhandledExceptionEventArgs e) {
            ExceptionLogger(e.ExceptionObject as Exception);
        });

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        log.Debug("Starting Application");
        Application.Run(mainForm = new MainForm());
    }

    private static void ExceptionLogger(Exception e) {
        log.Error("Unhandled Error", e);
        string errorMsg = "An application error occurred. Please contact the administrator with the following information:\n\n";
        errorMsg = errorMsg + e.Message + "\n\nStack Trace:\n" + e.StackTrace;
        if (MessageBox.Show(errorMsg, "TLMS Error", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Stop) == DialogResult.Abort)
            Application.Exit();
    }

异常处理程序似乎仅在我的代码中直接发生错误时起作用,但当错误直接在.NET库中发生时,处理程序不会被调用,而我希望处理程序对所有未处理异常都会被调用,包括我编写的代码之外的异常。
如果能够在事后在调试器中重现用户的确切步骤,则使用调试器跟踪错误非常有价值。然而,无论是独立运行还是在调试器内部运行,ExceptionLogger 都没有被调用,并且没有任何视觉指示表明发生了任何错误。由于异常被抑制,用户有时直到为时已晚才意识到他们所做的一切完全混乱,数据更加损坏。
应用程序平台正在x86上构建和运行(显然,如果在x64上运行,可能会丢失异常),并且已在64位和32位平台上进行了测试,但行为没有改变。

我们确实链接了一些较旧的Shockwave和Office库,尽管它们大部分时间都没有被使用。 - NaterTot
请查看此链接:https://dev59.com/3UbRa4cB1Zd3GeqP1Y2Q - ahazzah
ahazzah - 我已经将UnhandledExceptionMode从默认设置为其他值,并且可选的布尔参数并没有改变其行为(我尝试了true和false两种情况)。 - NaterTot
我对你的问题感到困惑,因为你实际上并没有提出一个问题。 - James
1
因为异常被抑制了...我认为其他的异常正在被处理,这就是为什么 ExceptionLogger 没有被调用的原因。搜索代码中的 catch 子句,如果终止比继续更好,则删除它们,否则在每个 catch 子句中添加日志记录代码。 - groverboy
显示剩余6条评论
1个回答

0

所以当应用程序在调试器中运行时,你只会看到“但未处理”这个错误。当它在调试器之外运行时,异常会被抑制。如果我理解正确的话,我仍然认为应用程序处理了这些异常,因为调试器有时会改变应用程序的行为。

我确认了InvalidCastException是一组异常中的一个,在.NET 4+中,如果异常上下文是非托管代码,它们会被以不同的方式处理。应用程序可以覆盖这种特殊处理(参见.NET 4中关于损坏状态异常的全部内容),但调试器可能会忽略这个覆盖。关于这个问题有很多网络资源,还可以参考MSDN Magazine上的一篇文章。

编辑:如果你的应用程序用户安装了.NET 3.5或更低版本,则应用程序无需应用上述资源中描述的覆盖。


我查看了整个应用程序,百分之百确定我的应用程序没有捕获到异常。感谢您的指引,我会研究一下 CSE 问题,看看是否是我所看到的问题。 - NaterTot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接