程序集反射加载和应用程序域冲突

时间:2017-04-04 17:59:15

标签: c# .net .net-assembly appdomain

我正在尝试制作一个小型C#工具来比较两个svn版本构建并跟踪任何类中的属性更改。我的目标是使用反射来比较我的dll的每个类的属性,而不使用Momo.Cecil。

通过实验,然后阅读本文Assembly Loading以及在Google上找到的一些主题,我了解到如果我们不使用Assembly.ReflectionOnlyLoadFrom,那么具有相同身份的两个DLL将被解析为相同。

尝试使用他们的代码为每次加载创建一个AppDomain,并尝试从搜索中获得许多变体,我得到了这个例外,我找不到解释如何解决这个问题的任何线程:

  

API限制:程序集'文件:/// D:\ somepath \ 82 \ MyLib.dll'已经从不同的位置加载。无法从同一appdomain中的新位置加载它。

在下一行的第二次调用(路径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 个答案:

答案 0 :(得分:1)

这可以通过在单独的appdomain中加载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
    }
 }