如何动态加载引用同一程序集的不同版本的dll

本文关键字:程序集 dll 版本 引用 何动态 动态 加载 | 更新日期: 2023-09-27 17:50:50

我们需要按顺序运行数据库更新。每个数据库更新将是它自己的DLL,并且需要保留对特定版本的域DLL的依赖(编写更新时的当前版本)。例如:

Cool.Program.Update0001.dll is dependent on Cool.Program.Domain.dll version 1.0.1
Cool.Program.Update0002.dll is dependent on Cool.Program.Domain.dll version 1.0.3
Cool.Program.Update0003.dll is dependent on Cool.Program.Domain.dll version 1.1.6

我的计划是存储这些dll &它们的依赖dll在子文件夹中,如下所示:

%APP%'Cool'Program'Updates'0001'Cool.Program.Update0001.dll
%APP%'Cool'Program'Updates'0001'Cool.Program.Domain.dll   (version 1.0.1)
%APP%'Cool'Program'Updates'0002'Cool.Program.Update0002.dll
%APP%'Cool'Program'Updates'0002'Cool.Program.Domain.dll   (version 1.0.3)
%APP%'Cool'Program'Updates'0003'Cool.Program.Update0003.dll
%APP%'Cool'Program'Updates'0003'Cool.Program.Domain.dll   (version 1.1.6)

然后让我的主程序加载&使用反射,按顺序动态调用每个Update DLL:

var path = System.IO.Path.GetDirectoryName(typeof(this).Assembly.Location) + "''Updates''" + versionNumber + "''Cool.Program.Update" + versionNumber + ".dll";
var assembly = System.Reflection.Assembly.LoadFile(path);
var type = assembly.GetTypes().First(x => x.Name == "Updater");
var method = type.GetMethod("DoYourThing");
var result = method.Invoke(null, dbConnection) as string;

不幸的是,在测试了这个设计并询问了版本号之后,我发现每个UpdateXXXX.dll都与LATEST Domain.dll一起工作,即使较早的一个存储在它自己的子文件夹中。我假设它们是通过GAC解决它们的依赖关系,或者,默认是主程序中已经加载的依赖关系。(顺便说一句,我看到在Visual Studio中,不可能强制"特定版本"作为项目参考,快速google-fu建议这不是直截了当的。)

我的问题:

我如何强制更新程序集将其对域dll的依赖关系解析到其本地文件夹?

或:

我可以显式地为动态加载的程序集注入依赖项吗?

编辑:我找到答案了,见下文

如何动态加载引用同一程序集的不同版本的dll

我将回答我自己的问题,因为我已经同时完成了它。

下面的代码是这样做的:

// versionNumber = "0001", "0002" etc
var basePath = Path.GetDirectoryName(typeof(this).Assembly.Location) + "''Updates''" + versionNumber + "''";
var updateAssemblyPath = Path.Combine(basePath, "Cool.Program.Update" + versionNumber + ".dll");
var setup = AppDomain.CurrentDomain.SetupInformation;
setup.ApplicationBase = basePath;
var newDomain = AppDomain.CreateDomain("Updater for " + versionNumber, null, setup);
var obj = (ICanDoSomething)newDomain.CreateInstanceFromAndUnwrap(updateAssemblyPath, "TestDynamicAssemblyLoading.Update"+ versionNumber + ".Class1");
var result = obj.TellMeYourVersionsAndDependencyVersions();
MessageBox.Show(result);

它假定所使用的类实现了一个已知的接口(例如;"ICanDoSomething")并继承自MarshalByRefObject:

public class Class1 : MarshalByRefObject, ICanDoSomething
{
    public string TellMeYourVersionsAndDependencyVersions()
    {
        return
            typeof(Class1).Assembly.GetName().Version + "'n'n" +
            "My reference to Domain'n================='n " + SomeModel.TellMeYourVersionsAndDependencyVersions() + "'n'n" +
            "My reference to Common'n================='n " + SomeUtility.TellMeYourVersion();
    }
}