MEF 调试
此章节来自msdn。
一、一般调试方法
在 Managed Extensibility Framework (MEF) 中调试问题可能非常困难,因为潜在问题与标准应用程序中的潜在问题不同。 本主题提供了特定于 MEF 的问题诊断技巧,并且提供了这些问题的一些可能原因。
发现 MEF 问题
解决 MEF 问题的第一步是在应用程序的 MEF 部分中定位问题。 下表列出了特定于 MEF 的问题。
问题 |
可能的原因 |
组合期间引发 ImportCardinalityMismatchException 异常。 |
由于部件缺失或被拒绝,无法使用匹配的导出填充导入。 - 或 - 预期单个导出的导入发现多个匹配项。 |
具有 ImportManyAttribute 特性的集合缺少预期内容。 |
预期部件缺失或被拒绝。 |
DefaultValueAttribute 特性设置为 true 的导入意外未填充。 |
预期的匹配项缺失或被拒绝。 |
处理异常和 DisableSilentRejection
MEF 旨在可靠地适应各种配置。 默认情况下,它忽略具有缺少必需的依赖项的部分。 但是,当您调试应用程序时,这种可靠性会使查找问题原因更困难。 您可以采用这些步骤更轻松地跟踪问题:
引发异常时,请配置 Visual Studio 调试器中断。
配置您的 CompositionContainer 对象禁用拒绝。
通常,如果应用程序引发异常,则 Visual Studio 调试器将中断执行仅当该异常不随后处理。 但是,您可能会发现,当引发异常时,立即停止并调试您的 MEF 应用程序会很有帮助,因为您的应用程序会以某些方式处理异常,而不会将其体现在调试器中。 若要在引发异常时配置 Visual Studio 调试器,在菜单栏上,选择“调试”、“异常”。 确保选择了所有异常的“引发”框,您想要将调试器设置为遇到这些异常时中断。 (有关 MEF,这些是在 System.ComponentModel.Composition 下的异常。这些异常此时将显示在调试器中,即使您的应用程序处理了这些异常。
默认情况下,MEF 使用叫做拒绝的处理确定将用于实例化调用哪些部件具有相关性。 组合引擎检查新部件的添加是否将导致组合失败。 如果它们可能会导致失败,则从容器中隐藏那些部件,但不引发异常。 在面对部署配置时此行为会使应用程序更稳定,但可能使调试更难。 若要每当部件被拒绝时关闭拒绝,并确保 MEF 引发异常,将 DisableSilentRejection 值设置传递到 CompositionContainer 或 ExportProvider 对象。 以下代码对此进行了说明:
代码段
var catalog = new DirectoryCatalog("Extensions");
var container = new CompositionContainer(catalog, CompositionOptions.DisableSilentRejection);
MEF 失败通常是级联的,即组合一个部件失败会导致组合第二个部件失败以此类推,直到观测到的失败点在异常的长列表中丢失。 为帮助诊断此属性的问题,CompositionException 异常提供 RootCauses 属性。 您可以检查在调试器中的此属性以查找是组合中每个错误的根本原因的异常。
跟踪
从开始 .NET Framework 4.5,MEF 支持跟踪。 运行时,以 Visual Studio 的调试模式,组合故障和异常将写入“IntelliTrace”窗口。 检查这些结果有助于诊断组合失败。 有关使用 IntelliTrace 的更多信息。
检查可用部件
若要确定哪些部件可用于目录,可以在调试器中检查目录的 Parts 属性,在代码中循环访问该属性。
如果希望看到的部件不存在,则表示未发现或者已拒绝这些部件。
如果可以看到一个部件,但是它与您希望它填充的导入不匹配,则表示出现了某种类型的不匹配。
导出/导入不匹配
为了使导出与特定导入匹配,必须满足以下所有条件。 如果未出现预期匹配,但是您已确认导出存在于目录中,请仔细检查这些条件。 手动构造协定以匹配特定导出时,这些条件也适用。
属性 |
匹配的条件 |
协定名称 |
必须完全匹配并且区分大小写。 如果协定名称是从类型推断得出的(例如,在没有任何参数的情况下应用 ExportAttribute 特性时),则唯一可能的匹配项是从同一类型推断得出的另一名称。 |
协定类型 |
必须完全匹配。 不支持多态匹配。 即使提供了匹配的协定名称,协定类型也必须匹配。 |
必需的元数据 |
导入通过其元数据视图的属性要求的所有元数据必须由导出通过 ExportMetadataAttribute 特性或自定义元数据特性提供。 元数据键(元数据视图中属性的名称)和元数据值的类型必须匹配。 |
创建策略 |
导出和导入不能指定不同的创建策略。 有关更多信息,请参见 CreationPolicy。 |
发现问题
如果部件未显示在目录中或者使用组合分析工具 (Mefx) 时未显示,则表示目录未发现该部件。 这里是导致此故障的一些可能原因:
该部件是抽象类型。 抽象类型不能用作部件。 使类型成为非抽象类型,或者创建非抽象子类型。
ImportingConstructorAttribute 特性缺失。 对于具有多个构造函数或者仅具有接受参数的构造函数的部件,必须指定一个构造函数,以便 MEF 使用 ImportingConstructorAttribute 特性。
该部件具有 PartNotDiscoverableAttribute 特性。 此特性阻止部件被发现。
该部件是开放式泛型类型。 MEF 不支持开放泛型。 请使用类型的封闭式子类,或者导出单个属性。
您使用 DirectoryCatalog 对象时可能出现其他故障:
该部件位于 .exe 文件中。 默认 DirectoryCatalog 仅从 DLL 文件读取。 通过使用相应搜索模式创建,可以使用 DirectoryCatalog 对象从其他文件读取。
部件的程序集具有缺失的引用。 使用的程序集不能从搜索路径(通常从它们自己的目录或者从全局程序集缓存)加载其引用。
该部件的程序集面向其他 CPU 类型。 MEF 不会加载面向错误 CPU 类型的程序集。
二、组合分析工具(Mefx)
组合分析工具 (Mefx) 是分析包含 Managed Extensibility Framework (MEF) 部件的库 (.dll) 和应用程序 (.exe) 文件的命令行应用程序。 Mefx 的主要目的是向开发人员提供一种方式,以允许他们无需向应用程序本身添加繁琐的跟踪代码即可诊断 MEF 应用程序中的组合故障。 它还可用于帮助了解第三方提供的库中的部件。 本主题描述如何使用 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
MEF 调试的更多相关文章
- MEF依赖注入调试小技巧!
自从哥的项目使用MEF以来,天天那个纠结啊,甭提了.稍有错误,MEF就报错,但就不告诉你哪错了,大爷的. 后来看了MEFX的相关调试方法,感觉也不太理想,根本不够直观的看到错误原因,也许是没有深入学习 ...
- 实战MEF(1):一种不错的扩展方式
在过去,我们完成一套应用程序后,如果后面对其功能进行了扩展或修整,往往需要重新编译代码生成新的应用程序,然后再覆盖原来的程序.这样的扩展方式对于较小的或者不经常扩展和更新的应用程序来说是可以接受的,而 ...
- C#进阶系列——MEF实现设计上的“松耦合”(一)
前言:最近去了趟外地出差,介绍推广小组开发的框架类产品.推广对象是本部门在项目上面的同事——1到2年工作经验的初级程序员.在给他们介绍框架时发现很多框架设计层面的知识他们都没有接触过,甚至没听说过,这 ...
- C#进阶系列——MEF实现设计上的“松耦合”(四):构造函数注入
前言:今天十一长假的第一天,本因出去走走,奈何博主最大的乐趣是假期坐在电脑前看各处堵车,顺便写写博客,有点收获也是好的.关于MEF的知识,之前已经分享过三篇,为什么有今天这篇?是因为昨天分享领域服务的 ...
- Prism 5 + MEF中的ModuleCatalog.CreateFromXaml问题
protected override IModuleCatalog CreateModuleCatalog() { return Microsoft.Practices.Prism.Modularit ...
- MEF核心笔记(6)让 MEF 拥抱 AOP
场景: 最近推荐同事在项目中使用起了 MEF,用其构建一个插件式的多人开发框架,因为该框架不是让我去设计了,所以对于 MEF 和 IOC 等概念不是很了解的同事,便会出现各种问题.接入 AOP 便是其 ...
- VS 本机调试
VS~通过IIS网站启用"域名"调试 在我们开发网站时,对某些信息进行序列化时,通常使用session,cookies,nosql等技术,而为了安全,我们在服务器上很多情况都做了防 ...
- 一周一话题之一(EF-CodeFirst、MEF、T4框架搭建学习)
本话题是根据郭明峰博客<MVC实用架构系列>的搭建学习总结. -->目录导航 一.数据仓储访问的构建 1.UnitOfWork的构建 2.Repository的构建 ...
- MEF 插件式开发之 DotNetCore 初体验
背景叙述 在传统的基于 .Net Framework 框架下进行的 MEF 开发,大多是使用 MEF 1,对应的命名空间是 System.ComponentModel.Composition.在 Do ...
随机推荐
- SSH整合之_架构的历史序列图
只用jsp最原始的架构 jsp+DB的2层架构 jsp+DB+_Entity的2层架构 jsp+DB+_Entity3_+Service的三层架构 jsp+DB+_Entity3_+Service_H ...
- 推荐一些C#相关的网站、资源和书籍 (转载自http://www.cnblogs.com/jiangxiaofan/p/3808316.html)
推荐一些C#相关的网站.资源和书籍 (转载自http://blog.csdn.net/chinacsharper/article/details/17514923) 一.网站 1.http://m ...
- C#多线程解决界面卡死问题
C#多线程解决界面卡死问题的完美解决方案 文章下最方有源码下载 问题描述:当我们的界面需要在程序运行中不断更新数据时, 当一个textbox的数据需要变化时, 对于这个问题可以先参考下我的另外一个文章 ...
- vsftp FTP服务器 server settings , and add different users
建议阅读知识:http://linux.vbird.org/linux_basic/0210filepermission.php 这是关于档案权限,用户,组等的问题.介绍的很有意思. 1. Inst ...
- SPL學習之SplDoublyLinkedList
Standard PHP Library(SPL)是官方提供的标准库,从php5.0.0开始已经默认实现在php中,我们可以类比它为ruby中的gem安装的包.spl里面实现了许多迭代器和数据结构对象 ...
- 克隆虚拟机win8系统后注意修改安全标识(SID)
克隆虚拟机win8系统后注意修改安全标识(SID) 克隆虚拟机系统后两个系统硬件配置一样,需要注意修改:security ID ,MAC,计算机名,IP地址,产品激活 重置工具:sysprep.e ...
- Java核心技术 卷Ⅰ 基础知识(2)
第四章 对象与类 基于类的访问权限 静态域 类的设计技巧
- PHP常用之封装分页工具类
分页基本上是每个项目都会使用到的,所以呢,把它封装成一个工具类,以后直接调用就可以了(虽然TP框架的灰常强大,但是自己封一个也未尝不可.),这样既省时又省力还赚'工分'. 我封的这个分页工具类还比较完 ...
- (七)第一个python程序!
这是对我自己来说比较有仪式的一篇随笔记录,说了那么多,开始第一个pyhton小程序吧! 首先找一个版本比较新的Linux系统, 执行Python –V 查看一下你的Python版本: # python ...
- USACO 3.4 Electric Fence
Electric FenceDon Piele In this problem, `lattice points' in the plane are points with integer coord ...