如何在.NET 8中捕获访问冲突异常并优雅地退出应用程序?
部分代码抛出 AccessViolationException;代码不在我的控制之下;我无法修复这个问题。当抛出这个异常时,我的应用程序会崩溃。我正在使用控制台应用程序和WinForms应用程序,两者使用相同的代码。两种变体中的问题都是一样的。
我清楚自己不能也不应该处理这个异常;这就是它会导致应用程序崩溃的原因。我可以在事件查看器中查看日志。我也不想处理这个异常;我只是想捕获它,以便写入日志,然后让应用程序以任意方式结束。因此应用程序崩溃不是我的问题。我需要在它崩溃之前写入日志,这样就不必去事件查看器查看到底哪里出错了。
我发现下面这些问题很有帮助:
Stack Overflow上还有其他几个相关问题在谈论这个问题;但它们都关于旧版.NET Framework。
在较旧版本的.NET Framework中,有一个设置需要在 app.config 中进行:
<runtime>
<legacyCorruptedStateExceptionsPolicy enabled="true" />
</runtime>
我尝试了这个,在.NET Framework 4中对我有用。
还有一个属性 [HandleProcessCorruptedStateExceptions],在.NET 8中已被弃用。我仍然尝试了它,但不起作用;应用程序仍然崩溃;下面是代码:
[HandleProcessCorruptedStateExceptions]
private bool MethodThatThrowsException(string filePath)
{
...
...
}
根据这些问题的回答,还可以使用另一个属性 [SecurityCritical];但它需要完全信任(Full Trust),这并非每次都可能实现。
在其中一个问题中解释的 COMPlus_legacyCorruptedStateExceptionsPolicy 环境变量方法也不起作用。在我的应用程序启动阶段添加以下代码仍然会使应用程序崩溃:
static class Program
{
[STAThread]
static void Main(string[] args)
{
Environment.SetEnvironmentVariable("COMPlus_legacyCorruptedStateExceptionsPolicy", "1");
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
看起来这些解决方案在.NET 8中已不再受支持:
https://github.com/dotnet/runtime/issues/12077#issuecomment-554933927
https://github.com/dotnet/runtime/issues/12077#issuecomment-555048590
所以唯一剩下的选项是 legacyCorruptedStateExceptionsPolicy。我想在面向.NET 8的应用程序中使用它。我应该在.NET 8中如何以及在哪里设置这个选项?在.NET 8中没有 app.config 文件。.runtimeconfig.json 是不是可行的方法?即便如此,如何在其中进行配置?
解决方案
下面是一个使用环境变量 COMPlus_legacyCorruptedStateExceptionsPolicy 的简单示例。
public static int Main(string[] args)
{
if (args.Length == 0)
{
Environment.SetEnvironmentVariable("COMPlus_legacyCorruptedStateExceptionsPolicy", "1");
Process.Start(Process.GetCurrentProcess().MainModule.FileName, "1");
}
else
{
try
{
ThrowException();
}
catch (AccessViolationException ex)
{
Console.WriteLine("Caught: " + ex);
}
}
return 0;
}
public static unsafe void ThrowException()
{
int* ptr = (int*)0x12345678;
*ptr = 1;
}
运行它时,会显示:
Caught: System.AccessViolationException: Attempted to read or write protected memory.