【发布时间】:2017-01-02 12:04:11
【问题描述】:
我的目标:
我正在编写一个 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 示例可以正常工作。
更新 作为一种解决方法,我只是移动了需要程序集在另一端(域内)运行的代码,然后将字符串返回,这可以很好地编组。不过,我会保持这个问题的开放性,因为我想知道是否有针对实际问题的解决方案。
【问题讨论】:
-
好吧,您又回到了第一方,因为程序集现在已加载到 both AppDomains 中,而您只能
Unload()其中一个。为什么不在您的辅助 AppDomain 中完成所有需要完成的工作? -
@MickyD 根据问题的更新,这就是我最终要做的。但我不喜欢它:/
-
不喜欢?这就是 AppDomains 的全部意义所在。如果您创建一个子线程来执行冗长的任务但只是阻止等待它完成,那么创建一个用于隔离的 Appdomain 以加载一个程序集或插件只是为了将其返回到父域会以完全相同的方式破坏沙箱的目的.我建议您在 MSDN 杂志重新应用域上阅读一些好文章
标签: c# .net-assembly appdomain