程序集反射加载和应用程序域冲突
Posted
技术标签:
【中文标题】程序集反射加载和应用程序域冲突【英文标题】:Assembly reflection loading and app domain conflict 【发布时间】:2017-04-04 17:59:14 【问题描述】:我正在尝试制作一个小型 C# 工具来比较两个 svn 修订版本并跟踪任何类中的属性更改。我的目标是在不使用 Momo.Cecil 的情况下使用反射来比较我的 dll 的每个类的属性。
通过实验,然后阅读这篇文章 Assembly Loading 和在 Google 上找到的一些线程,我了解到如果我们不使用 Assembly.ReflectionOnlyLoadFrom
,两个具有相同身份的 DLL 将被解析为相同。
尝试使用他们的代码为每次加载创建一个 AppDomain,并尝试从搜索中获得许多变体,我得到了这个异常,我找不到任何线程来解释如何解决这个问题:
API 限制:程序集 'file:///D:\somepath\82\MyLib.dll' 已从其他位置加载。无法从同一应用域中的新位置加载。
此错误发生在以下行的第二次调用(路径 82)上:
Assembly assembly = Assembly.ReflectionOnlyLoadFrom(assemblyPath);
也许我不了解一些非常基本的东西,这使我无法正确创建新的 AppDomain?
这是用于重现此问题的所有代码。
我的入口点的代码
//Let say one of the property has been renamed between both commits
var svnRev81Assembly = ReflectionOnlyLoadFrom(@"D:\somepath\81\MyLib.dll");
var svnRev82Assembly = ReflectionOnlyLoadFrom(@"D:\somepath\82\MyLib.dll");
加载器的实现
private string _CurrentAssemblyKey;
private Assembly ReflectionOnlyLoadFrom(string assemblyPath)
var path = Path.GetDirectoryName(assemblyPath);
// Create application domain setup information.
AppDomainSetup domaininfo = new AppDomainSetup();
domaininfo.ApplicationBase = path;
domaininfo.PrivateBinPath = path;
_CurrentAssemblyKey = Guid.NewGuid().ToString();
AppDomain currentAd = AppDomain.CreateDomain(_CurrentAssemblyKey, null, domaininfo); //Everytime we create a new domain with a new name
//currentAd.ReflectionOnlyAssemblyResolve += CustomReflectionOnlyResolver; This doesnt work anymore since I added AppDomainSetup
currentAd.SetData(_CurrentAssemblyKey, path);
//Loading to specific location - folder 81 or 82
Assembly assembly = Assembly.ReflectionOnlyLoadFrom(assemblyPath);
//Preloading the
foreach (var assemblyName in assembly.GetReferencedAssemblies())
Assembly.ReflectionOnlyLoadFrom(Path.Combine(path, assemblyName.Name + ".dll"));
Type[] types = assembly.GetTypes();
// Lastly, reset the ALS entry and remove our handler
currentAd.SetData(_CurrentAssemblyKey, null);
//currentAd.ReflectionOnlyAssemblyResolve -= CustomReflectionOnlyResolver; This doesnt work anymore since I added AppDomainSetup
return assembly;
【问题讨论】:
【参考方案1】:这可以通过在单独的应用程序域中加载 dll 来解决。
private static void ReflectionOnlyLoadFrom()
var appDomain = AppDomain.CreateDomain("Temporary");
var loader1 = (Loader)appDomain.CreateInstanceAndUnwrap(typeof(Loader).Assembly.FullName, typeof(Loader).FullName);
loader1.Execute(@"D:\somepath\81\MyLib.dll");
var loader2 = (Loader)appDomain.CreateInstanceAndUnwrap(typeof(Loader).Assembly.FullName, typeof(Loader).FullName);
loader2.Execute(@"D:\somepath\82\MyLib.dll");
loader1.CompareTwoDLLs(loader2);
AppDomain.Unload(appDomain);
Loader.cs
public class Loader : MarshalByRefObject
public Assembly TempAssembly get; set;
public string Execute(string dllPath)
TempAssembly = Assembly.LoadFile(dllPath);
return TempAssembly.FullName;
public void GetRefAssemblyTypes()
foreach (var refAssembly in TempAssembly.GetReferencedAssemblies())
var asm = Assembly.Load(refAssembly);
var asmTypes = asm.GetTypes();
public void CompareTwoDLLs(Loader l2)
var types1 = TempAssembly.GetTypes();
var types2= l2.TempAssembly.GetTypes();
GetRefAssemblyTypes();
//logic to return comparison result
【讨论】:
嗨,我玩过你的解决方案,它确实适用于一些基本的 dll。一旦 dll 有依赖关系,它就没有。我确实尝试在 Execute 方法中为 TempAssembly.GetReferenceAssemblies() 添加 Assembly.LoadFile,但它给出“无法加载文件或程序集或其依赖项之一。系统找不到指定的文件。”尝试执行 GetTypes() 时。 使用 Loader,您可以跨应用程序域边界进行通信。我可以通过在加载器类中添加这个方法来获取引用的程序集。使用 GetRefAssemblyTypes 方法编辑了我的答案。以上是关于程序集反射加载和应用程序域冲突的主要内容,如果未能解决你的问题,请参考以下文章