【问题标题】:How to dynamically load DLLs which reference different versions of same assembly?如何动态加载引用同一程序集不同版本的 DLL?
【发布时间】:2014-04-25 07:40:28
【问题描述】:

我们需要按顺序运行数据库更新。每个数据库更新都将是它自己的 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)

然后让我的主程序加载并使用反射按顺序动态调用每个更新 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 的依赖解析为其本地文件夹?

或者:

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

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

【问题讨论】:

    标签: c# reflection transactions dependencies assemblies


    【解决方案1】:

    我会回答我自己的问题,因为我已经完成了。

    这段代码可以解决问题:

    // 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();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2010-09-08
      • 2010-09-18
      • 2010-10-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-22
      • 1970-01-01
      • 2011-05-25
      相关资源
      最近更新 更多