MEF组合问题

8
我无法解决一个看起来很基本的MEF问题:我有两个“插件”项目(我们称之为P1和P2),以及一个对两个插件都通用的第三个项目(我们称之为C)。P1和P2都引用C。当尝试导入位于P1中的组件时,它会失败,因为此组件依赖于位于C中的组件。以下是跟踪信息: System.ComponentModel.Composition Warning: 1: 可组合部分定义'MyCompany.Client.Pms.Plugin.InclusionList.ViewModel.InclusionListViewModel'已被拒绝。组成保持不变。更改被拒绝,因为出现了以下错误:组成产生多个组成错误,其中有4个根本原因。下面提供了根本原因。有关更详细的信息,请查看CompositionException.Errors属性。 1) 没有找到与约束匹配的导出项'((exportDefinition.ContractName = "MyCompany.Client.Plugins.Common.Controls.Selectors.PortfolioSelectors.ViewModel.ICalypsoBookSelectorViewModel") && (exportDefinition.Metadata.ContainsKey("ExportTypeIdentity") && "MyCompany.Client.Plugins.Common.Controls.Selectors.PortfolioSelectors.ViewModel.ICalypsoBookSelectorViewModel".Equals(exportDefinition.Metadata.get_Item("ExportTypeIdentity"))))'。 导致:无法在部分'MyCompany.Client.Pms.Plugin.InclusionList.ViewModel.InclusionListViewModel'上设置导入项'MyCompany.Client.Pms.Plugin.InclusionList.ViewModel.InclusionListViewModel.CalypsoBookSelectorViewModel(ContractName="MyCompany.Client.Plugins.Common.Controls.Selectors.PortfolioSelectors.ViewModel.ICalypsoBookSelectorViewModel")'。 元素:MyCompany.Client.Pms.Plugin.InclusionList.ViewModel.InclusionListViewModel.CalypsoBookSelectorViewModel(ContractName="MyCompany.Client.Plugins.Common.Controls.Selectors.PortfolioSelectors.ViewModel.ICalypsoBookSelectorViewModel")--> MyCompany.Client.Pms.Plugin.InclusionList.ViewModel.InclusionListViewModel --> DirectoryCatalog(Path="C:\Work\mmtrader\dashboard\Code\Src\Dashboard\MM\Trader\bin\Debug\Plugins\Positions") [...](其他3个问题完全相同,只是针对不同的视图模型)我查看了MEF目录,结果MEF知道这些视图模型,所以我不知道缺少什么。根据Dennis的要求,以下是我的导入/导出: 导出:
Export(typeof(ICalypsoBookSelectorViewModel))]
public class CalypsoBookSelectorViewModel : ScreenWithCleanupLifecycle, ICalypsoBookSelectorViewModel
{...}

导入:

[Import(typeof(ICalypsoBookSelectorViewModel))]
public ICalypsoBookSelectorViewModel CalypsoBookSelectorViewModel { get; set; }

同时也需要考虑目录:

目录

非常感谢您的帮助!

4个回答

9
我终于找到了问题所在,与MEF指责的CalypsoBookSelectorViewModel无关。
事实上,这个ViewModel依赖于另一个组件(CalypsoBookSelectorModel),而这个组件又依赖于IDispatcher组件。
问题是,这个IDispatcher组件被指定了一个合同名称(见下文),被导出了两次(每个插件中一次),因此MEF无法确定使用哪一个。 当然,真正的问题是,MEF应该告诉我这个问题,而不是把责任推给链条上面的一个类。
感谢Dennis查看这个问题,我希望这会帮助其他遇到相同问题的人。
Dispatcher导入:
[Import(DispatcherNames.BackgroundDispatcherName, typeof(IDispatcher))]
public IDispatcher Dispatcher { get; set; }

@AntoineJaussoin:但是MEF告诉你这个问题啊!:) 仔细查看输出窗口,你会看到类似于“找到了多个与约束匹配的导出项”(取决于IDispatcher)的信息,当构建该部分时。当然,如果该部分没有被组合,依赖的部分也不会被构建。不幸的是,我不知道如何在这里发布代码示例以重现此消息。 - Dennis
可能我们正在使用旧版本的MEF,我会尝试更新它。也许新版本会提供更多的调试信息。 - Antoine Jaussoin
@AntoineJaussoin:我正在使用.NET 4中的MEF。有趣的是查看完整的MEF跟踪(如何启用它:http://blogs.msdn.com/b/dsplaisted/archive/2010/07/13/how-to-debug-and-diagnose-mef-failures.aspx)。 - Dennis
那么,长期来看,你如何避免这个问题呢? - Gusdor
我也遇到了同样的问题,但是找不到DispatcherNames.BackgroundDispatcherName。这是什么? - Ziggler
显示剩余4条评论

6

您的 P1C 中导入了一些内容(更确切地说是 ICalypsoBookSelectorViewModel)。

当 MEF 容器试图创建 P1 时,它也会尝试解析所有与之相关联的导入项。因此,它会在其自身的目录和父级导出提供程序中搜索 ICalypsoBookSelectorViewModel 类型(确实是合同名称,但在本例中并不重要)的导出。

如果找不到这样的导出(这就是您的情况),MEF容器将保持组成不变。
要修复这个问题,您应该将 [Export(typeof(ICalypsoBookSelectorViewModel))] 添加到相应类型的定义中。

当然,所有这些都意味着您的目录和导出提供程序(如果有)已正确初始化。

请注意,这些导出定义不相等

public interface IA {}

[Export(typeof(IA))] // contract name is "IA"
public class A : IA {}

[Export] // contract name is "A"
public class A : IA {}

[Export]
public class Composed
{
    [Import] // MEF will search for exports like [Export(typeof(IA))]
    private IA field1;

    [Import] // MEF will search for exports like [Export]
    private A field1;
}

嗨Dennis,非常感谢您的回复!问题在于,导出已经在实现类上正确设置了:[Export(typeof(ICalypsoBookSelectorViewModel))] public class CalypsoBookSelectorViewModel:ScreenWithCleanupLifecycle,ICalypsoBookSelectorViewModel - Antoine Jaussoin
再次您好,我看了您编辑过的答案,我理解了所有内容:我相信我的导入/导出属性是正确的,它们正确地定义了接口等。另一方面,似乎MEF有点欺骗我,因为我开始认为问题不是直接与我的ICalypsoBookSelectorViewModel有关,而是与另一个更深层次的导入有关(MEF没有告诉我)。如果这个线索有所发展,我会再联系您。 - Antoine Jaussoin
我刚刚在原问题中添加了导入/导出功能。 - Antoine Jaussoin
@AntoineJaussoin:你的导入/导出定义看起来没问题;你能发布一些在MEF容器中使用过的目录部分(例如,调试器截图)吗?我不相信奇迹... - Dennis
我在原始问题上发布了截图。我也不相信奇迹,但今天可能是我的幸运日 ;) - Antoine Jaussoin
我找到了问题,当然与视图模型组件无关...MEF对调试并不是很有帮助。我会在另一个答案中发布我的发现。 - Antoine Jaussoin

0
我在遇到这个问题后一直在寻找解决方案。我意识到我在导出类上使用了System.Composition而不是System.ComponentModel.Composition

0

出现错误是因为他使用了[Import],如果要导入多个,则应该使用[ImportMany]


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接