MEF Composition Error Because of Assembly Names?
提前感谢您审阅此问题!
我正在使用MEF在项目中加载一些程序集。在我们更改包含接口的文件名之前,一切都很好。
为了更清楚地说明这一点,我将总结出工作的场景,然后总结出工作不正常的场景,然后具体说明异常和导致不工作场景中异常的代码。
以下是工作场景:
我们有一个名为iplugin的接口,它在名为common-1-0.dll的程序集中定义。
我们有一些插件程序集是根据common-1-0.dll编译的。
加载插件的应用程序是根据common-1-0.dll编译的。
以下是非工作场景:
我们有一个名为iplugin的程序集,它在名为common-1-1.dll的程序集中定义。接口没有从common-1-0.dll更改。
我们有一些插件程序集是根据common-1-0.dll编译的。
加载插件的应用程序是根据common-1-1.dll编译的。
现在的问题是:
当我在第二个场景中运行下面的代码时,会得到一个compositionexception(显示在下面的代码下)。这似乎是因为插件是根据common-1-0.dll编译的,而试图进行组合的应用程序是根据common-1-1.dll编译的。代码中的任何内容在两个文件之间都没有改变,只有名称。
因此,我们希望能够加载针对任何程序集构建的插件,只要该程序集导出正确的接口,但我不确定是否可以用MEF实现。这就是这个问题的结果,我想知道的。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | private void LoadPlugins(string directory, string searchPattern ="", bool recursive = false) { Trace.Agent.Status("Loading plugin(s) from {0}{1}{2}", directory, Path.DirectorySeparatorChar, searchPattern); try { var directoryCatalog = string.IsNullOrEmpty(searchPattern) ? new DirectoryCatalog(directory) : new DirectoryCatalog(directory, searchPattern); _container = new CompositionContainer(new AggregateCatalog(directoryCatalog)); _container.ComposeParts(this); } catch (CompositionException exc) { Trace.Agent.Exception(exc); } if (recursive) { foreach (string dir in Directory.GetDirectories(directory)) { LoadPlugins(Path.Combine(directory, dir), recursive:true); } } } |
组合例外:
导出"testplugin.testplugin(contractname="common.iplugin")不能分配给类型"common.iplugin"。
我想我找到了解决你的问题的方法,虽然有点老套,但无论如何。
因此,如果您对程序集进行了不同的命名,例如assembly1.0和assembly1.1,这会导致问题,因为您不能简单地将程序集重定向到新版本。通常,您只需保留相同的程序集名称并增加版本号。通过这种方式,您可以在没有任何问题的情况下重定向(只要代码支持它)。
解决方案是通过附加到当前AppDomain的
1 2 3 4 5 6 7 | AppDomain currentDomain = AppDomain.CurrentDomain; currentDomain.AssemblyResolve += new ResolveEventHandler(MyResolveEventHandler); LoadPlugins(currentDomain.BaseDirectory); var x = _container.GetExport<IPlugin>().Value; |
在事件处理程序中,您可以简单地返回"new"程序集
1 2 3 4 5 6 7 8 | private static Assembly MyResolveEventHandler(object sender, ResolveEventArgs args) { if (args.Name.StartsWith("PluginCore1.0")) { return typeof(IPlugin).Assembly; } return null; } |
这也适用于没有签名的程序集(没有公钥标记)。
要触发解析事件,您仍然需要在app.config中定义程序集重定向,但是:
1 2 3 4 5 6 7 | <dependentAssembly> <assemblyIdentity name="PluginCore1.0" culture="neutral" /> <bindingRedirect oldVersion="1.0.0.0" newVersion="1.1.0.0" /> </dependentAssembly> </assemblyBinding> |
同样,我强烈建议使用相同的程序集名称(不带版本后缀),并且只使用程序集重定向机制,这种机制应该可以正常工作。