如何在特定异常时终止 .NET 应用程序 - 可能没有堆栈展开?
How to terminate .NET application on a specific exception - possibly without stack unwinding?
我有一个由 C# 和 C++ 代码组成的 .NET 应用程序(服务)。
"Crashes"(即System.AccessViolationException
等Corrupted State Exceptions)在C++代码中会被("non-")正确处理,它们会直接导致我的AppDomain.CurrentDomain.UnhandledException
处理程序(记录日志),然后应用程序将终止,如果这样配置(它是),则写入一个 WER 转储文件。
对于这个应用程序,我确定 System.NullReferenceException
始终是一个错误,尤其是 因为一些 C++/CLI 访问冲突错误会报告这个错误而不是 AV .
有没有办法让 .NET 不 在异常边界上捕获 NullReferenceException
(在这种情况下是我的 OnTimer
回调)而是直接终止应用程序,没有展开堆栈,基本上"jumping"直接到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);
}
}
Immediately terminates a process after writing a message to the Windows Application event log, and then includes the message in error reporting to Microsoft.
和
This method terminates a process without running any active try/finally blocks or finalizers.
很明显,在 CurrentDomain_FirstChanceException
中,您可以复制您在 UnhandledException
中可能拥有的日志记录代码(或者有一个由两者调用的通用方法)
FirstChanceException
实际上是一个 "simple" 全局异常过滤器这一事实让我走上了轨道(是否是 "right" 轨道还有待观察):
我们在 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
显然,要使其正常工作,您需要进行更多配置,但这似乎正是我想要的。 :-)
我有一个由 C# 和 C++ 代码组成的 .NET 应用程序(服务)。
"Crashes"(即System.AccessViolationException
等Corrupted State Exceptions)在C++代码中会被("non-")正确处理,它们会直接导致我的AppDomain.CurrentDomain.UnhandledException
处理程序(记录日志),然后应用程序将终止,如果这样配置(它是),则写入一个 WER 转储文件。
对于这个应用程序,我确定 System.NullReferenceException
始终是一个错误,尤其是 因为一些 C++/CLI 访问冲突错误会报告这个错误而不是 AV .
有没有办法让 .NET 不 在异常边界上捕获 NullReferenceException
(在这种情况下是我的 OnTimer
回调)而是直接终止应用程序,没有展开堆栈,基本上"jumping"直接到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);
}
}
Immediately terminates a process after writing a message to the Windows Application event log, and then includes the message in error reporting to Microsoft.
和
This method terminates a process without running any active try/finally blocks or finalizers.
很明显,在 CurrentDomain_FirstChanceException
中,您可以复制您在 UnhandledException
中可能拥有的日志记录代码(或者有一个由两者调用的通用方法)
FirstChanceException
实际上是一个 "simple" 全局异常过滤器这一事实让我走上了轨道(是否是 "right" 轨道还有待观察):
我们在 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
显然,要使其正常工作,您需要进行更多配置,但这似乎正是我想要的。 :-)