关于c#:找到了多个与MEF ImportMany匹配约束异常的导出

More than one export was found that matches the constraint exception with MEF ImportMany

我正在尝试调试WPF应用程序上的程序集导入问题,该应用程序使用MEF加载一些插件,并寻找解决此特定异常的方法:

More than one export was found that matches the constraint:
ContractName MarkPad.Contracts.ISpellingService
RequiredTypeIdentity MarkPad.Contracts.ISpellingService

只有一个程序集直接引用concern的插件作为它的autopac注册的一部分(代码片段在最后)。

1
2
3
4
5
[ImportingConstructor]
public SpellCheckPlugin(
    IPluginSettingsProvider settingsProvider,
    ISpellingService spellingService,
    ISpellCheckProviderFactory spellCheckProviderFactory)

EDOCX1[0]只有1个实现

1
2
[Export(typeof(ISpellingService))]
public class SpellingService : ISpellingService

这是GitHub上的一个开源代码52项目。

插件导入是:

1
2
[ImportMany]
IEnumerable<IPlugin> plugins;

到目前为止我所做的尝试:

  • 这篇博文和这篇博文提到使用[ImportMany(AllowRecomposition = true)],但这似乎也没有帮助。
  • 我发现的其他讨论提到了将"copy local"设置为false,但因为它实际上用于注册代码中,这不是一个选项,因为它最终不会出现在输出文件夹中。
  • 有什么想法吗?

    引用插件的注册代码

    1
    2
    3
    4
    5
    6
    7
    8
    builder.RegisterType<SpellingService>().As<ISpellingService>()
        .SingleInstance()
        .OnActivating(args =>
    {
        var settingsService = args.Context.Resolve<ISettingsProvider>();
        var settings = settingsService.GetSettings<SpellCheckPlugin.SpellCheckPluginSettings>();
        args.Instance.SetLanguage(settings.Language);
    })


    解决方案

    问题是一个bug,当前通过GetExecutingAssembly的程序集在pluginmanager()中用作AggregateCatalog中提供给CompositionContainer的目录项之一。

    1
    2
    3
    4
    var catalog = new AggregateCatalog();

    // This was causing the composition to detect additional imports
    catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));

    这个bug是从将服务/插件提取到它们自己的程序集中产生的,这些程序集最初是核心MarkPad程序集的一部分。

    Credit goes to @shiftkey and this patch.

    额外改进

    作为这个补丁的一部分,有一些额外的清理可能有助于支持这个答案。

    由于spellcheckplugin采用了接口,因此导出仅被移动到接口本身,而不是具体类型。

    1
    2
    3
    4
    5
    [ImportingConstructor]
    public SpellCheckPlugin(
        IPluginSettingsProvider settingsProvider,
        ISpellingService spellingService,
        ISpellCheckProviderFactory spellCheckProviderFactory)

    而是在接口上添加导出

    1
    2
    3
    4
    5
    6
    7
    [InheritedExport]
    public interface ISpellCheckProviderFactory

    // and

    [InheritedExport]
    public interface ISpellingService

    移除混凝土出口

    1
    2
    3
    4
    5
    6
    7
    [Export(typeof(ISpellingService))]
    public class SpellingService : ISpellingService

    // and

    [Export(typeof(ISpellCheckProviderFactory))]
    public class SpellCheckProviderFactory : ISpellCheckProviderFactory