我的目标:
我正在编写一个vsix(Visual Studio扩展),我想编译一个项目,然后加载生成的.dll并通过反射检查它。由于代码的编写方式,我无法使用ReflectionOnlyLoad()
。如果我只是Assembly.Load
,那么文件将被锁定,直到用户重新启动整个IDE。
我正在尝试根据我在网上找到的样本设置一个单独的AppDomain。
它的要点是:
1.我创建了一个代理类,它将整理AppDomain
个实例中的数据:
internal class AppDomainProxy : MarshalByRefObject
{
public Assembly GetAssembly(string assemblyPath)
{
return Assembly.LoadFile(assemblyPath);
}
}
然后我创建了一个实例:
var domaininfo = new AppDomainSetup { ApplicationBase = System.Environment.CurrentDirectory, ShadowCopyDirectories = "true", ShadowCopyFiles = "true", LoaderOptimization = LoaderOptimization.MultiDomainHost };
var adevidence = System.AppDomain.CurrentDomain.Evidence;
var domain = System.AppDomain.CreateDomain("reflection", adevidence, domaininfo);
var proxyType = new AppDomainProxy().GetType();
var proxyInstance = (AppDomainProxy)domain.CreateInstanceFromAndUnwrap(proxyType.Assembly.Location, proxyType.FullName);
var loadedAssembly = (proxyInstance as AppDomainProxy).GetAssembly(this._assemblyLocation);
这无法将透明代理转换为AppDomainProxy
类型。
要解决此问题,可以轻松提供如下的程序集解析器:
this.domain.AssemblyResolve += CurrentDomainOnAssemblyResolve;
private Assembly CurrentDomainOnAssemblyResolve(object sender, ResolveEventArgs args)
{
var loadedAssemblies = System.AppDomain.CurrentDomain.GetAssemblies();
foreach (var assembly in loadedAssemblies)
{
if (assembly.FullName == args.Name)
{
return assembly;
}
}
return null;
}
这个工作正常,我的代理是演员。
但是,当我调用我的方法时,再次调用CurrentDomainOnAssemblyResolve
,向我建议Assembly
属性不是真正可序列化的,因此.net只是试图在原始端加载程序集,从而得到与Assembly.Load
相同的问题。这很容易看到,因为像return AppDomain.Current.FriendlyName;
这样的简单Microsoft样本工作得很好。
更新作为一种解决方法,我只是移动了我需要程序集在另一端(域内)运行的代码,然后返回编组好的字符串。不过,我会保持这个问题,因为我想知道是否有实际问题的解决方案。
答案 0 :(得分:0)
当然,您需要将需要使用程序集的代码移动到单独的AppDomain
。没有任何魔法 - 如果你需要使用引用程序集中的类型,你需要加载该程序集。
在AppDomain
边界(以及其他远程处理方案)中编组对象的主要方法有两种:要么创建对象的副本,要么编组所有方法调用。两者都非常棘手 - 您必须确保永远不会泄漏引用程序集中的类型,否则您需要将其加载到两个域中。在您的情况下,您无法封送方法调用,因为Assembly
不(并且不能)MarshalByRefObject
- 您的代理必须返回真实的Assembly
对象,并且无法创建编组代理。
要获得适当的隔离,必须避免从您不想共享的程序集中泄漏任何类型,以及可能暴露任何类型的非可编组类型。这通常意味着如果你负担得起,就可以从共享库中坚持原语和类型。保持一个很好的紧密接口,并尽量不要过多地利用“自动”编组 - 将一个自动代理返回到一个复杂的对象很方便,但是要让它更难理解界面的范围。该对象是否具有从非共享程序集返回类型的方法?太糟糕了,您还需要在您的域中加载它。
通常,使用多个实际互操作的AppDomain(以及相关的.NET远程处理)是一个巨大的痛苦。它很复杂,容易出错,很难做对。您可以阅读有关该主题的全书。有一个原因是为什么不再推荐使用它们 - 以及PCL不支持它们的原因(很长一段时间,Mono都没有支持)。它们仍然有用吗?是啊。软件隔离具有非常好的好处。但你需要非常小心,不要搞砸了:)