问题描述
我正在实现支持插件的应用程序.目前,当我尝试加载由宿主应用程序和插件使用的通用程序集时出现问题:宿主应用程序应该使用该程序集的一个版本,而插件使用另一个版本.这是由应用程序升级决定的进程 - 插件可以与宿主应用程序分开更新.
I'm implementing application that supports plugins. Currently the problem arises when I try to load common assembly that is used both by host application and plugin: host application should use one version of that assembly, while plugin uses another version. This is dictated by application upgrade process - plugin can be updated separately from host application.
每个程序集都经过签名,因此我使用强名称来加载程序集.
Every assembly is signed, so I use strong names for loading assemblies.
我创建了一个测试应用程序来演示该问题.插件程序集位于宿主应用程序的子文件夹插件"中.Plugin文件夹包含插件实现DLL、插件声明接口DLL和CommonLib DLL.宿主应用程序还使用插件声明 DLL 和 CommonLib DLL(位于文件夹树中的 1 级).
I created a test application which demonstrates the problem. Plugin assemblies are located in subfolder 'Plugin' of host application. Plugin folder contains the plugin implementation DLL, plugin declaration interface DLL and CommonLib DLL. Host application also use plugin declaration DLL and CommonLib DLL (located 1 level up in folder tree).
这里是插件加载的源代码:
Here is source code of plugin loading:
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
据我所知,插件仍然尝试在宿主应用程序文件夹中查找 CommonLib 程序集(忽略我在创建 AppDomain 时提供的 appBasePath 参数),但在那里找到了较旧的 1.0.8 版本并生成此错误.如何强制插件从插件文件夹加载引用的程序集 - 使用强名称时无法指定要加载的完整程序集路径.
As I udnerstand, plugin still tries to find CommonLib assembly in the host application folder (ignoring the appBasePath parameter I provided when creating AppDomain), but finds older version 1.0.8 there and generates this error. How can I force plugin to load referenced assemblies from Plugin folder - there is no way to specify full assembly path to load when using strong name.
推荐答案
我认为您的问题如下:
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(它的程序集已经加载到不同版本中).
With this you're loading the updated/outdated type references into the main AppDomain (which has the assembly already loaded in a different version).
我建议您使用以下方法:
I recommend you use the following approach:
- 创建一个单独的程序集,其中包含合同/接口.此程序集已修复并始终保持在特定版本,永远不会过时,您的插件的每个版本都可以引用它.
- 编写一个程序集加载器,它是您的主机应用程序的一部分,但也是一个单独的程序集.此程序集加载程序程序集不得引用应用程序的其余部分,以便您可以在新的应用程序域中进行设置.
- 设置新的应用程序域后,加载您的 AssemblyLoader 实例.这个加载插件程序集并与之交互.
- 您的应用程序不与程序集本身交互.您的应用程序通过应用程序域边界调用您的 AssemblyLoader,而 AssemblyLoader 调用插件
我不能说这是否是最好的版本,但是在每个插件都可以加载任何程序集的任何版本的环境中,这个版本对我来说效果很好.通过这种设置,您几乎可以抵抗更改版本或更新,并且每个插件都可以使用它想要的版本.
I can't say if this is the best version possible, but this one works pretty well for me in an environment where each plugin can load any version of any assembly. With this setup you're pretty much resistant to changing versions or updates and each plugin can use the version it wants.
告诉我它是否适合您.
这篇关于将不同版本的程序集加载到单独的 AppDomain 中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!