如何在特定异常上终止 .NET 应用程序 - 可能无需展开堆栈



我有一个由C#和C++代码组成的.NET应用程序(服务)。

"崩溃"(即 C++ Code 中的System.AccessViolationException和其他损坏状态异常)将得到正确处理("非"),它们将直接导致我的AppDomain.CurrentDomain.UnhandledException处理程序(记录),然后应用程序将终止,如果配置如此,则写入 WER 转储文件(确实如此)。

对于此应用程序,我已经确定System.NullReferenceException始终是一个错误,特别是因为某些 C++/CLI 访问违规错误将报告此错误而不是 AV。

有没有办法让 .NET 不在异常边界上捕获NullReferenceException(在这种情况下是我的OnTimer回调),而是直接终止应用程序,而无需展开堆栈,基本上直接"跳"到AppDomain.CurrentDomain.UnhandledException

你可以:

AppDomain.CurrentDomain.FirstChanceException += CurrentDomain_FirstChanceException;

然后

static void CurrentDomain_FirstChanceException(object sender, FirstChanceExceptionEventArgs e)
{
    if (e.Exception is NullReferenceException)
    {
        Environment.FailFast("FailFast", e.Exception);
    }
}

Environment.FailFast

将消息写入 Windows 应用程序事件日志后立即终止进程,然后将该消息包含在向Microsoft报告的错误中。

此方法在不运行任何活动的 try/finally 块或终结器的情况下终止进程。

显然,在CurrentDomain_FirstChanceException中,您可以复制UnhandledException中可能具有的日志记录代码(或者具有由两者调用的通用方法)

FirstChanceException实际上是一个"简单"的全局异常过滤器这一事实让我走上了正轨(它是否是"正确"的轨道还有待观察):

我们已经在 CLI 中有了异常筛选器

如果一个人有在 C# 6 中工作的奢侈,那么它就像:

        try
        {
            throw new NullReferenceException("No, Really");
        }
        catch(Exception ex) when (FilterExType(ex))
        {
            Console.WriteLine($"2: Caught 'any' exception: {ex}");
        }
    static bool FilterExType(Exception ex)
    {
        if (ex is NullReferenceException)
        {
            Environment.FailFast("BOOM from C#!", ex);
        }
        // always handle if we return
        return true;
    }

对于我们这些(像我一样)坚持使用早期版本的人,我们可以通过委托/lambda通过 VB.NET 路由过滤:

        try {
            VbFilterLib.FilteredRunner.RunFiltered(() =>
            {
                throw new NullReferenceException("Via VB.NET");
            });
        } 
        catch (Exception ex)
        {
            Console.WriteLine("1: Caught 'any' exception: {0}", ex");
        }

使用VB(请耐心等待,VB.NET 远非我精通的语言):

Public Class FilteredRunner
    Delegate Sub VoidCode()
    Private Shared Function FilterAction(x As Exception) As Boolean
        If TypeOf x Is NullReferenceException Then
            Environment.FailFast("Abort program! Investigate Bug via crash dump!", x)
        End If
        ' Never handle here:'
        Return False
    End Function
    Public Shared Sub RunFiltered(code As VoidCode)
        Try
            code.Invoke()
        Catch ex As Exception When FilterAction(ex)
            Throw New InvalidProgramException("Unreachable!", ex)
        End Try
    End Sub
End Class

显然,要使其工作,您需要更多配置绑定,但这似乎正是我想要的。

相关内容

最新更新