加载不同版本组装成独立的应用程序域(Load different version of assemb

2019-10-29 03:34发布

我执行的应用程序,支持插件。 目前,问题就出现了,当我尝试加载由主机应用程序和插件的使用这两种常见的组件:主机应用程序应当使用组件的一个版本,而插件使用另一个版本。 这是由应用程序升级过程决定 - 插件可以独立于主机应用程序进行更新。

每个组件签署,所以我使用的加载程序集强名称。

我创建了一个测试应用程序演示了此问题。 插件组件位于主机应用程序的子文件夹“插件”。 插件文件夹包含插件实现DLL,插件声明DLL接口和CommonLib DLL。 主机应用程序也可以使用插件声明DLL和CommonLib DLL(在文件夹树位于1级以上)。

这里是插件加载的源代码:

static void Main(string[] args)
{
    Console.WriteLine("Host   says: {0}", GreetingManager.SayHello("Sasha"));
    Console.WriteLine("Host   says: {0}", GreetingManager.SayGoodBye("Sasha"));
    var pluginDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugin");
    var pluginFile = Directory.GetFiles(pluginDir).First(f => f.EndsWith("Plugin.dll"));

    Assembly asmr = Assembly.ReflectionOnlyLoadFrom(pluginFile);

    AppDomain pluginDomain = AppDomain.CreateDomain("Plugin", null, pluginDir, "", false);

    pluginDomain.Load(asmr.FullName);

    Assembly asm = pluginDomain.GetAssemblies().First(a => a.GetName().Name == "Plugin");
    Type p = asm.GetTypes().First(t => t.GetInterfaces().Contains(typeof(IPlugin)));

    var pluginInstance = (IPlugin)pluginDomain.CreateInstanceAndUnwrap(asm.FullName, p.FullName);
    Console.WriteLine("Plugin says: {0}", pluginInstance.TransformString("Sasha"));
}

它抛出异常:

Unhandled Exception: System.IO.FileLoadException: Could not load file or assembly 'CommonLib, Version=1.0.9.0, Culture=neutral, PublicKeyToken=73c7c163a33b622c' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
   at Plugin.MyPlugin.TransformString(String str)
   at PluginBackwardCompatibilityTest.Program.Main(String[] args) in D:\Projects\Test\PluginBackwardCompatibilityTest\PluginBackwardCompatibilityTest\Program.cs:line 37

正如我udnerstand,插件仍然试图找到在主机应用程序文件夹CommonLib组件(忽略创建的AppDomain时,我提供的appBasePath参数),但发现旧版本1.0.8有与产生此故障。 我如何可以强制插件从插件文件夹中加载引用的组件 -有没有办法来指定使用强名称时加载完整的装配路径。

Answer 1:

我觉得你的问题如下:

Assembly asm = pluginDomain.GetAssemblies().First(a => a.GetName().Name == "Plugin");
Type p = asm.GetTypes().First(t => t.GetInterfaces().Contains(typeof(IPlugin)));
var pluginInstance = (IPlugin)pluginDomain.CreateInstanceAndUnwrap(asm.FullName, p.FullName);

有了这个你加载更新/过时的类型引用到主AppDomain中(已装载在不同版本的程序集)。

我建议您使用以下方法:

  1. 创建一个包含合同/接口一个单独的程序。 本届大会是固定并保持在一个特定版本的所有时间,它永远是过时的和你的插件的每个版本可以参考它。
  2. 编写一个汇编加载器是您的主机应用程序的一部分,但在一个单独的装配以及。 该组件装载器组件一定不能有你的应用程序的其余任何引用,以便您可以在新的AppDomain设置。
  3. 建立新的应用程序域后,加载AssemblyLoader的一个实例。 这一个加载插件组件,并与之交互。
  4. 您的应用程序不符合大会本身交互。 你的应用程序通过应用程序域边界调用你AssemblyLoader和AssemblyLoader调用插件

我不能说这是否是最好的版本可能的,但是这一次工作得很好,我在一个环境中,每个插件可以加载任何组件的任何版本。 有了这个设置你几乎耐改变版本或更新,每一个插件可以使用它想要的版本。

请让我知道这对你有没有用。



Answer 2:

最有可能的是你自己的代码,先加载最新版本-检查是否CommonLib被调用之前正确加载到新的应用程序域Load

如果是这样的话,你需要在你的主代码链接到非常小心CommonLib避免加载最新版本为时尚早。 你甚至可能需要使用后期绑定/反射它。



文章来源: Load different version of assembly into separate AppDomain