我有一个由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
显然,要使其工作,您需要更多配置绑定,但这似乎正是我想要的。