结构分析工具 (Mefx)

组合分析工具 (Mefx) 是分析包含 Managed Extensibility Framework (MEF) 部件的库 (.dll) 和应用程序 (.exe) 文件的命令行应用程序。 Mefx 的主要目的是向开发人员提供一种方式,以允许他们无需向应用程序本身添加繁琐的跟踪代码即可诊断 MEF 应用程序中的组合故障。 它还可用于帮助了解第三方提供的库中的部件。 本主题描述如何使用 Mefx 并且提供了语法参考。

本主题包括下列各节。

  • 获取 Mefx
  • 基本语法
  • 列出可用部件
  • 列出导入和导出
  • 查找拒绝的部件
  • 分析主要原因
  • 白名单

获取 Mefx

可在 Codeplex 的 Managed Extensibility Framework 上获取 Mefx。 下载和解压缩该工具即可。

基本语法

Mefx 从命令行使用以下格式调用:

mefx [files and directories] [action] [options]

第一组参数指定从中加载部件进行分析的文件和目录。 使用 /file: 开关指定文件,使用 /directory: 开关指定目录。 可以指定多个文件或目录,如下面的示例所示:

mefx /file:MyAddIn.dll /directory:Program\AddIns [action...]
注意注意

每个 .dll 或 .exe 应仅加载一次。如果多次加载一个文件,该工具可能会返回不正确的信息。

在文件和目录列表后面,必须指定命令以及该命令的任何选项。

列出可用部件

使用 /parts 操作可列出在加载的文件中声明的所有部件。 结果为简单的部件名称列表。

mefx /file:MyAddIn.dll /parts
MyAddIn.AddIn
MyAddIn.MemberPart

若要获取有关部件的更多信息,请使用 /verbose 选项。 这将输出所有可用部件的更多信息。 若要获取有关单个部件的更多信息,请使用 /type 操作而不是 /parts。

mefx /file:MyAddIn.dll /type:MyAddIn.AddIn /verbose
[Part] MyAddIn.MemberPart from: AssemblyCatalog (Assembly=" MyAddIn, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
  [Export] MyAddIn.MemberPart (ContractName=" MyAddIn.MemberPart")

列出导入和导出

/imports 和 /exports 操作将分别列出所有导入的部件和所有导出的部件。 还可以使用 /importers 或 /exporters 操作列出导入或导出特定类型的部件。

mefx /file:MyAddIn.dll /importers:MyAddin.MemberPart
MyAddin.AddIn

还可以对这些操作应用 /verbose 选项。

查找拒绝的部件

加载可用的部件后,Mefx 使用 MEF 组合引擎组合它们。 不能成功组合的部件称为“拒绝的部件”。 若要列出所有拒绝的部件,请使用 /rejected 操作。

可以将 /verbose 选项与 /rejected 操作结合使用,以输出有关拒绝的部件的详细信息。 在下面的示例中,ClassLibrary1 DLL 包含 AddIn 部件,它导入 MemberPart 和 ChainOne 部件。 ChainOne 导入 ChainTwo,但是 ChainTwo 不存在。 这意味着 ChainOne 被拒绝,这将导致 AddIn 被拒绝。

mefx /file:ClassLibrary1.dll /rejected /verbose

下面显示了前面的命令的完整输出:

[Part] ClassLibrary1.AddIn from: AssemblyCatalog (Assembly="ClassLibrary1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
  [Export] ClassLibrary1.AddIn (ContractName="ClassLibrary1.AddIn")
  [Import] ClassLibrary1.AddIn.memberPart (ContractName="ClassLibrary1.MemberPart")
    [SatisfiedBy] ClassLibrary1.MemberPart (ContractName="ClassLibrary1.MemberPart") from: ClassLibrary1.MemberPart from: AssemblyCatalog (Assembly="ClassLibrar
y1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
  [Import] ClassLibrary1.AddIn.chain (ContractName="ClassLibrary1.ChainOne")
    [Exception] System.ComponentModel.Composition.ImportCardinalityMismatchException: No valid exports were found that match the constraint '((exportDefinition.ContractName == "ClassLibrary1.ChainOne") AndAlso (exportDefinition.Metadata.ContainsKey("ExportTypeIdentity") AndAlso "ClassLibrary1.ChainOne".Equals(exportDefinition.Metadata.get_Item("ExportTypeIdentity"))))', invalid exports may have been rejected.
   at System.ComponentModel.Composition.Hosting.ExportProvider.GetExports(ImportDefinition definition, AtomicComposition atomicComposition)
   at Microsoft.ComponentModel.Composition.Diagnostics.CompositionInfo.AnalyzeImportDefinition(ExportProvider host, IEnumerable`1 availableParts, ImportDefinition id)
    [Unsuitable] ClassLibrary1.ChainOne (ContractName="ClassLibrary1.ChainOne")
from: ClassLibrary1.ChainOne from: AssemblyCatalog (Assembly="ClassLibrary1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
      [Because] PartDefinitionIsRejected, The part providing the export is rejected because of other issues.

[Part] ClassLibrary1.ChainOne from: AssemblyCatalog (Assembly="ClassLibrary1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
  [Primary Rejection]
  [Export] ClassLibrary1.ChainOne (ContractName="ClassLibrary1.ChainOne")
  [Import] ClassLibrary1.ChainOne.chain (ContractName="ClassLibrary1.ChainTwo")
    [Exception] System.ComponentModel.Composition.ImportCardinalityMismatchException: No valid exports were found that match the constraint '((exportDefinition.ContractName == "ClassLibrary1.ChainTwo") AndAlso (exportDefinition.Metadata.ContainsKey("ExportTypeIdentity") AndAlso "ClassLibrary1.ChainTwo".Equals(exportDefinition.Metadata.get_Item("ExportTypeIdentity"))))', invalid exports may have been rejected.
   at System.ComponentModel.Composition.Hosting.ExportProvider.GetExports(ImportDefinition definition, AtomicComposition atomicComposition)
   at Microsoft.ComponentModel.Composition.Diagnostics.CompositionInfo.AnalyzeImportDefinition(ExportProvider host, IEnumerable`1 availableParts, ImportDefinition id)

需要关注的信息包含在 [Exception] 和 [Unsuitable] 结果中。 [Exception] 结果提供有关部件为什么被拒绝的信息。 [Unsuitable] 结果指明以其他方式匹配的部件为什么无法用于填充导入;在本例中,因为该部件本身因缺失导入被拒绝。

分析主要原因

如果一些部件链接在较长的依赖关系链中,则问题涉及的部件靠近底部时可能会导致整个链被拒绝。 诊断这些问题可能非常困难,因为故障的根本原因并不总是非常明显。 为了帮助诊断问题,可以使用 /causes 操作,它尝试查找所有级联拒绝的根本原因。

对前面的示例使用 /causes 操作仅列出 ChainOne 的信息,它未填充导入是拒绝 AddIn 的根本原因。 /causes 操作可以在正常和 /verbose 选项中使用。

注意注意

在大多数情况下,Mefx 能够诊断出级联故障的根本原因。然而,对于部件以编程方式添加到容器的情况、涉及分层容器的情况或者涉及自定义 ExportProvider 实现的情况,Mefx 将无法诊断出原因。通常,应尽可能避免前面所述的情况,因为故障通常很难诊断。

白名单

/whitelist 选项允许您指定一个文本文件,其中列出应该被拒绝的部件。 然后,将标记意外拒绝。 分析不完整的库或者缺少一些依赖项的子库时,这可能非常有用。 /whitelist 选项可应用于 /rejected 或 /causes 操作。

请考虑一个名为 test.txt 的文件,它包含文本“ClassLibrary1.ChainOne”。 如果对前面的示例运行带有 /whitelist 选项的 /rejected 操作,则将生成以下输出:

mefx /file:ClassLibrary1.dll /rejected /whitelist:test.txt
[Unexpected] ClassLibrary1.AddIn
ClassLibrary1.ChainOne