【问题标题】: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;
    }

【问题讨论】:

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


    【解决方案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 方法编辑了我的答案。
    猜你喜欢
    • 1970-01-01
    • 2016-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多