我的目标是:编写一个v6 (Visual扩展),其中我想编译一个项目,然后加载生成的.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;
这样简单的微软示例工作得很好。
更新作为一个解决方案,我只是移动了我的代码,需要程序集在另一边运行(在域内),然后返回字符串,它可以很好地封送。不过,我会保留这个问题,因为我想知道是否有解决实际问题的办法。
发布于 2017-01-02 13:02:28
当然,您需要将处理程序集的代码移动到单独的AppDomain
。这没有什么神奇之处--如果您需要处理来自引用程序集的类型,则需要加载该程序集。
跨AppDomain
边界(和其他远程处理场景)编组对象的主要方法有两种:要么创建对象的副本,要么封送所有方法调用。这两种方法都非常棘手--您必须确保不会泄漏引用程序集中的类型,否则需要将其加载到两个域中。在您的示例中,您不能封送方法调用,因为Assembly
不是(也不能是)一个MarshalByRefObject
--您的代理必须返回一个真实的Assembly
对象,并且不能创建编组代理。
要获得适当的隔离,必须避免从不希望共享的程序集中泄漏任何类型,以及可能公开其中任何类型的不可封送处理类型。这通常意味着如果您负担得起共享库中的原语和类型的话。保持一个良好的紧密接口,不要过多地利用“自动”编组--将自动代理返回到复杂对象是很方便的,但会使理解接口的范围变得更加困难。对象是否有从非共享程序集返回类型的方法?太糟糕了,您也需要在您的域中加载它。
通常,使用实际互操作的多个AppDomains (以及相关的.NET远程处理)是一个巨大的痛苦。它很复杂,容易出错,而且很难纠正。你可以阅读关于这一主题的整本书。不再推荐使用它们是有原因的,也是PCL不支持它们的原因(而且很长一段时间以来,Mono不支持它们)。它们还有用吗?嗯。软件隔离有非常好的好处。但是你需要非常小心,不要把事情搞砸:)
https://stackoverflow.com/questions/41426509
复制相似问题