将多个程序集版本加载到多个 AppDomain 中

Posted

技术标签:

【中文标题】将多个程序集版本加载到多个 AppDomain 中【英文标题】:Load multiple assembly versions into multiple AppDomains 【发布时间】:2017-10-08 11:42:19 【问题描述】:

我的目标是在该程序集的多个版本上执行一些使用特定程序集的“一段代码”。我这样做的方式是在单独的 AppDomain 上执行那段“代码”,每个程序集版本一个。

只有当“一段代码”通过反射使用程序集时,我才能做到这一点,但我想要的是拥有那段“一段代码” >" 以强类型方式编写。

换句话说,假设我有以下程序集:

namespace ClassLibrary1

    public class Class1
    
        internal const string Version = "1.0.0.0";
        public string Method1()  return Version; 
    

在 AssemblyInfo.cs 中也有如下定义:

[assembly: AssemblyVersion(ClassLibrary1.Class1.Version)]

现在假设我有一个“版本”文件夹,其中包含该程序集的多个版本,例如:

/Versions/
├─ /1000/
│   └─ ClassLibrary1.dll
├─ /1001/
│   └─ ClassLibrary1.dll
└─ /1002/
    └─ ClassLibrary1.dll  

现在要执行“一段代码”,我正在使用以下控制台应用程序:

class Program

    static void PieceOfCode(Assembly assembly)
    
        Type class1Type = assembly.GetType("ClassLibrary1.Class1");
        dynamic class1 = Activator.CreateInstance(class1Type);
        string vesion = class1.Method1();

        Console.WriteLine(vesion);
    

    public sealed class SeparateDomainExecutor : MarshalByRefObject
    
        public void Execute(Action<Assembly> action, string assemblyPath)
        
            action(Assembly.LoadFrom(assemblyPath));
        
    

    static void Main(string[] args)
    
        foreach (string file in Directory.EnumerateFiles(@"C:\Versions", "*.dll", SearchOption.AllDirectories))
        
            AppDomain domain = AppDomain.CreateDomain("ClassLibrary1 Domain");

            var type = typeof(SeparateDomainExecutor);
            var runner = (SeparateDomainExecutor)domain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName);
            runner.Execute(PieceOfCode, file);

            AppDomain.Unload(domain);
        

        Console.Read();
    

控制台应用程序工作正常,但我想将“PieceOfCode”中的反射用法替换为以下内容:

static void PieceOfCode()

    ClassLibrary1.Class1 class1 = new ClassLibrary1.Class1();
    Console.WriteLine(class1.Method1());

这可能吗?

我遇到的问题是 PieceOfCode 将使用 ClassLibrary1 的某个特定版本(可能是最新版本)编写,我看不出如何在单独的 AppDomain 中“覆盖”该版本。 我尝试了几件事,但总是以 FileLoadException 告终。

【问题讨论】:

如果它是一个强命名程序集并且您在加载应用程序之前就知道版本,您可以使用绑定重定向并在 app/web .config 文件中更改版本 “强类型”与“多个版本”截然相反。 .NET 通过在类型标识中包含程序集的版本号来实现强类型检查。强大的 DLL Hell 对策,但显然您想通过设计来制造地狱。所以你根本不想这样做。 是的,完全正确。基本上,我想忽略 dll-hell 保护,即强名称。 【参考方案1】:

不幸的是,当您在一段静态类型的代码中编写ClassLibrary1.Class1 时,您需要一个程序集引用,而编译器使用该引用来命名该类的给定版本。尽管完全限定名称 (typeof(Class1).AssemblyQualifiedName) 不包含程序集的路径或文件名,仅包含程序集名称和版本,但您可能会注意到,类加载器还有更多限制:

它不能将来自不同程序集的同名的 2 个类加载到同一个命名空间中 由于路径或文件名不是程序集引用的一部分,因此您不能引用具有相同强名称的 2 个程序集编译时

您使用Assembly.LoadFrom(...) 和动态绑定的方式是我能想到的最好的方式。这就是通常从集成它们的应用程序处理不同版本的 Office 程序集的方式。

我看到的唯一可能的解决方案是将一段代码分离到一个单独的程序集中(例如,MyStaticIntegration.dll)针对每个版本的依赖项(ClassLibrary1.dll)分别编译它,然后集成将 MyStaticIntegration.dll 的每个版本添加到您的应用程序中的方式与之前使用 ClassLibrary1.dll 的方式相同。

相同的动态墙将保留在您的应用程序中,但您可以使用此技巧来缩小您正在动态使用的界面。

【讨论】:

感谢您的回复,很遗憾您确认了我的担忧。不过,感谢您提出的解决方案。

以上是关于将多个程序集版本加载到多个 AppDomain 中的主要内容,如果未能解决你的问题,请参考以下文章

从字节数组加载时找不到 AppDomain 程序集

是否可以避免将一些程序集加载到“AppDomain”中?

多个 AppDomain 之间的交互。销毁单例对象的问题

将代理对象克隆到当前 AppDomain

如果在同一个 AppDomain 中加载了多个版本,WPF 无法选择正确的 DLL

程序集无法加载到受限的 AppDomain