gpt4 book ai didi

c# - 处理来自子 AppDomain 的不可序列化的未处理异常

转载 作者:太空狗 更新时间:2023-10-29 21:55:38 24 4
gpt4 key购买 nike

我们使用 System.AddIn 将加载项加载到单独的子 AppDomain 中,如果加载项 AppDomain 有未处理的异常,我们将卸载它。

因为 .NET 2.0 版的默认行为是在任何 AppDomain 有未处理的异常时拆除整个进程,我们通过在我们的 App.config 中使用“legacyUnhandledExceptionPolicy”选项然后手动拆除进程来做到这一点如果未处理的异常在主 AppDomain 中,或者如果它在加载项中则卸载相应的 AppDomain。

这一切都很好,除了一个小问题:未处理的异常总是从子 AppDomain 冒泡到主 AppDomain,如果它们不可序列化,它们就无法成功跨越 AppDomain 边界。

相反,我们得到一个 SerializationException,在主 AppDomain 中显示为 UnhandledException,导致我们的应用程序自行崩溃。

对于这个问题,我能想到几个可能的解决方案:

  • 我们无法为未处理的 SerializationExceptions 拆除进程(糟糕)。

  • 我们可以阻止异常从子 AppDomain 传播到主 AppDomain。

  • 我们可以用可序列化的异常替换不可序列化的异常,也许使用序列化代理和序列化绑定(bind)器。 [编辑:请参阅结尾了解为什么无法使用代理人]

然而,第一个非常糟糕,我一直未能弄清楚如何使用跨 AppDomain 远程处理其他选项。

有人可以提供一些建议吗?感谢您的帮助。

要使用以下 App.config 重现创建控制台应用程序:

<?xml version="1.0"?>
<configuration>
<runtime>
<legacyUnhandledExceptionPolicy enabled="true"/>
</runtime>
</configuration>

以及以下代码:

class Program
{
private class NonSerializableException : Exception
{
}

static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += MainDomain_UnhandledException;

AppDomain childAppDomain = AppDomain.CreateDomain("Child");
childAppDomain.UnhandledException += ChildAppDomain_UnhandledException;

childAppDomain.DoCallBack(
() => new Thread(delegate() { throw new NonSerializableException(); }).Start());

Console.ReadLine();
}

static void MainDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Console.WriteLine("Main AppDomain Unhandled Exception: " + e.ExceptionObject);
Console.WriteLine();
}

static void ChildAppDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Console.WriteLine("Child AppDomain Unhandled Exception: " + e.ExceptionObject);
Console.WriteLine();
}
}



编辑:我使用反射器查看是否有任何方法可以访问跨 AppDomain 远程处理中使用的 BinaryFormatter,但它最终出现在 CrossAppDomainSerializer 类中的这段代码中:

internal static void SerializeObject(object obj, MemoryStream stm)
{
BinaryFormatter formatter = new BinaryFormatter();
RemotingSurrogateSelector selector = new RemotingSurrogateSelector();
formatter.SurrogateSelector = selector;
formatter.Context = new StreamingContext(StreamingContextStates.CrossAppDomain);
formatter.Serialize(stm, obj, null, false);
}

所以它在方法中本地创建了格式化程序,显然没有办法附加我自己的代理...我认为这使得在那个方向上的任何更多努力都是徒劳的。

最佳答案

我会处理远程应用程序域中的异常。首先,我将使用异常处理代码创建一个新程序集,然后将其加载到子应用程序域中。

下面的代码应该会给出一些想法。

class Program {
private class NonSerializableException : Exception { }

static void Main(string[] args) {
var childAppDomain = AppDomain.CreateDomain("Child");
Console.WriteLine("Created child AppDomain #{0}.", childAppDomain.Id);

// I did not create a new assembly for the helper class because I am lazy :)
var helperAssemblyLocation = typeof(AppDomainHelper).Assembly.Location;
var helper = (AppDomainHelper)childAppDomain.CreateInstanceFromAndUnwrap(
helperAssemblyLocation, typeof(AppDomainHelper).FullName);
helper.Initialize(UnloadHelper.Instance);

childAppDomain.DoCallBack(
() => new Thread(delegate() { throw new NonSerializableException(); }).Start());

Console.ReadLine();
}

private sealed class UnloadHelper : MarshalByRefObject, IAppDomainUnloader {
public static readonly UnloadHelper Instance = new UnloadHelper();

private UnloadHelper() { }

public override object InitializeLifetimeService() {
return null;
}

public void RequestUnload(int id) {
// Add application domain identified by id into unload queue.
Console.WriteLine("AppDomain #{0} requests unload.", id);
}
}
}

// These two types could be in another helper assembly

public interface IAppDomainUnloader {
void RequestUnload(int id);
}

public sealed class AppDomainHelper : MarshalByRefObject {
public void Initialize(IAppDomainUnloader unloader) {
AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
unloader.RequestUnload(AppDomain.CurrentDomain.Id);
}
}

关于c# - 处理来自子 AppDomain 的不可序列化的未处理异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5463525/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com