我试图使用AppDomains以便在我的应用程序中隔离和运行代码。我需要做的是为每个客户端创建新的AppDomain,并在该AppDomain下,我需要创建另一个类的实例,其中包含需要隔离的代码。我还需要以某种方式存储创建的实例,以便稍后创建它的同一客户机再次调用时可以访问它。我现在创建它的方法是:
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
,它告诉我:"在此上下文中不支持获取透明代理的运行时类型。"
这是完全错误的方法还是只是一些小错误?如果我的方法是完全错误的,还有其他的方法来实现我的目标吗?
编辑
显然,IsolatedClass
本身有一些问题-它继承了另一个继承了MarshallByRefObject的类。当我创建了一个简单的虚拟类,并按照Kentonbmax的指令进行操作时,它起作用了。我将继续测试,看看真正的问题是什么。
我尝试了这个,唯一的区别是我的类在不同的库中。如果你想与不同的类类型进行交互,你可以用MarshalByRefObject代替IsolatedClass作为字典中的值类型。
var domain = AppDomain.CreateDomain(typeof(MyType).Assembly.FullName);
var proxy = domain.CreateInstanceAndUnwrap(
typeof(MyType).Assembly.FullName,
typeof(MyType).FullName) as MyType;
UnhandledException和DomainUnload事件在你的IsolatedClass是一个很好的方式来处理任何资源在你的IsolatedClass卸载你的AppDomains。另外,我建议使用'as'代替直接强制转换,这样你就可以检查强制转换是否失败,而不会抛出InvalidCast异常。
使用。first是有问题的,因为您不能保证键存在,因此可以返回空引用。如果你在调用Initialize时知道clientId为什么在调用DoSomething时不知道呢?
if(_isolatedClassesList.ContainsKey(clientId)
{
MyType mine = _isolatedClassesList[clientId] as MyType;
mine.MyMethod();
}