存储在 AppDomain 下创建的对象实例

Storing instance of object created under AppDomain

我正在尝试使用 AppDomains 以便在我的应用程序中隔离和 运行 代码。 我需要做的是为每个客户端创建新的 AppDomain,在该 AppDomain 下,我需要创建另一个 class 的实例,其中包含需要隔离的代码。我还需要以某种方式存储创建的实例,以便稍后在创建它的同一客户端再次调用时可以访问它。 我现在创建它的方式是这样的:

private Dictionary<string, IsolatedClass> isolatedClassesList = new Dictionary<string, IsolatedClass>();

public void Initialize(string clientId)
{
    AppDomain appDomain = AppDomain.CreateDomain("New AppDomain");

    IsolatedClass isolatedClass = (IsolatedClass)appDomain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, typeof(IsolatedClass).FullName);

    isolatedClass.Initialize(clientId);

    isolatedClassesList.Add(clientId, isolatedClass);
}

AppDomain 的创建和“Initiliaze(clientId)”方法的首次调用工作正常。还将它存储在字典中(供以后使用),没有任何例外。

稍后尝试获取先前创建的IsolatedClass实例时出现问题,例如:

public void DoSomething (string clientId)
{
    IsolatedClass isolatedClass = isolatedClassesList.First(x => x.Key == clientId).Value;

    isolatedClass.RunIsolatedMethod();
}

它抛出空引用异常(它无法检索实例)。当我在那里放置一个断点并检查字典中的内容时,对于 Value,它显示:"Obtaining the runtime type of a transparent proxy is not supported in this context."

这是完全错误的方法还是只是一些小错误? 如果我的方法完全错误,有没有其他方法可以实现我的目标?


编辑

显然,IsolatedClass 本身存在一些问题 - 它继承自另一个 class,后者继承自 MarshallByRefObject。当我创建简单的虚拟 class 并按照 Kentonbmax 的指令进行时,它起作用了。 我会继续测试,看看真正的问题是什么。

我试过了,唯一的区别是我的 class 在不同的库中。如果您想要与之交互的不同 class 类型,您可以将 IsolatedClass 替换为 MarshalByRefObject 作为字典中的值类型。

var domain = AppDomain.CreateDomain(typeof(MyType).Assembly.FullName);

                    var proxy = domain.CreateInstanceAndUnwrap(
                        typeof(MyType).Assembly.FullName,
                        typeof(MyType).FullName) as MyType;

IsolatedClass 中的 UnhandledException 和 DomainUnload 事件是卸载 AppDomain 时处理 IsolatedClass 中任何资源的好方法。此外,我建议使用 'as' 而不是直接转换,这样您就可以检查转换是否失败而不会抛出 InvalidCast 异常。

使用 .First 是有问题的,因为您不能保证密钥存在,因此可以取回空引用。如果您在调用 Initialize 时知道 clientId,为什么在调用 DoSomething 时不知道它?

if(_isolatedClassesList.ContainsKey(clientId)
{
    MyType mine = _isolatedClassesList[clientId] as MyType;
    mine.MyMethod();
}