提前感谢您审核此问题!
我正在使用MEF在项目中加载一些程序集。在我们更改包含界面的文件的名称之前,一切都运行良好。
为了更清楚,我将总结事情有效的场景,然后是事情不起作用的场景,然后专门显示异常以及在无法工作的场景中导致异常的代码。
以下是工作方案:
我们有一个名为IPlugin的接口,它在名为Common-1-0.dll的程序集中定义。
我们有一些针对Common-1-0.dll编译的插件程序集。
加载插件的应用程序是针对Common-1-0.dll进行编译的。
以下是非工作方案:
我们在一个名为Common-1-1.dll的程序集中定义了一个名为IPlugin的IPlugin。该接口没有从Common-1-0.dll更改。
我们有一些针对Common-1-0.dll编译的插件程序集。
加载插件的应用程序是针对Common-1-1.dll编译的。
现在问题:
当我在第二个场景中运行下面的代码时,我得到一个CompositionException(显示在下面的代码中)。它似乎是由于插件是针对Common-1-0.dll编译的,而尝试编写该组合的应用程序是针对Common-1-1.dll编译的。代码中的任何内容都没有在两个文件之间发生变化,只是名称。
所以我们希望能够加载针对任何程序集构建的插件,只要该程序集导出正确的接口,但我不确定我是否可以使用MEF执行此操作。这是我想通过这个问题得知的。
代码:
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);
}
}
}
CompositionException:
导出'TestPlugin.TestPlugin(ContractName =“Common.IPlugin”)'不能分配给'Common.IPlugin'。
答案 0 :(得分:2)
我认为我找到了解决问题的方法,但无论如何都有点被黑了。
因此,如果您对程序集的命名方式不同,例如assembly1.0和assembly1.1会导致问题,因为您不能简单地将程序集重定向到新版本。 通常,您只需保留相同的程序集名称并增加版本号。这样您就可以重定向而不会出现任何问题(只要代码支持它)。
解决方案是通过附加到当前AppDomain的AssemblyResolve
事件来破解程序集解析机制。
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += new ResolveEventHandler(MyResolveEventHandler);
LoadPlugins(currentDomain.BaseDirectory);
var x = _container.GetExport<IPlugin>().Value;
在事件处理程序中,您只需返回“新”程序集
即可 private static Assembly MyResolveEventHandler(object sender, ResolveEventArgs args)
{
if (args.Name.StartsWith("PluginCore1.0"))
{
return typeof(IPlugin).Assembly;
}
return null;
}
这样做,也没有签名的程序集(没有公钥标记)。
要触发resolve事件,您仍然需要在app.config中定义程序集重定向:
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="PluginCore1.0"
culture="neutral" />
<bindingRedirect oldVersion="1.0.0.0" newVersion="1.1.0.0" />
</dependentAssembly>
</assemblyBinding>
同样,我强烈建议使用相同的程序集名称(没有版本后缀),只需使用应该正常工作的程序集重定向机制。