选择MEF和MAF(System.AddIn)

托管扩展性框架(MEF)和托管添加框架(MAF,又名System.AddIn)似乎完成了非常类似的任务。 根据这个堆栈溢出的问题, 是MEF的替代System.Addin? ,你甚至可以同时使用两者。

你什么时候选择使用一个而不是另一个? 在什么情况下,你会选择一起使用?

我一直在评估这些选项,这里是我来到的结论。

MAF是一个真正的插件框架。 你可以完全分开你的插件,甚至在一个单独的应用程序域中运行它们,这样如果一个插件崩溃,它不会取消你的应用程序。 它还提供了一个非常完整的方式,从而取决于任何东西,而不是你给他们的合同。 事实上,在升级主应用程序时,您可以对合约适配器进行版本化,以便向旧插件提供向后兼容性。 虽然这听起来不错,但为了跨越应用程序域,您必须付出沉重的代价。 您可以快速支付这个价格,也可以灵活地支付您可以来回发送的类型。

MEF更像是依赖注入,还有一些额外的好处,比如可发现性和…(在这个上空白)。 MAF所具有的隔离度在MEF中不存在。 对于两个不同的事物,它们是两个不同的框架。

Danielg说的很好。 我会补充一点:

如果你观看关于System.Addins的视频,他们正在谈论非常大的项目。 他谈到了管理主机应用程序的一个团队,管理每个AddIn的另一个团队以及管理合同和管道的第三个团队 。 基于此,我认为System.Addins显然适用于更大的应用程序。 我正在考虑像SAP这样的ERP系统这样的应用程序(可能不是那么大,但你明白了)。 如果您观看了这些视频,则可以看出使用System.Addins的工作量非常大。 如果你有很多公司为你的系统编写第三方加载项,并且你不能破坏任何这些附加合同而受到处罚,那么这样做会很好。

另一方面,MEF似乎与SharpDevelop的插件方案,Eclipse插件架构或Mono.Addins有更多的相似之处。 这比System.Addins更容易理解,我相信它会更加灵活。 你失去的东西是你没有得到AppDomain隔离或强大的版本控制合同开箱即用的MEF。 MEF的优势在于,您可以将整个应用程序作为零部件的组成部分进行构建,因此,您可以针对不同的客户以不同的配置发运产品,如果客户购买了新功能,则只需将该功能部件放到安装目录并且应用程序看到它并运行它。 它也有利于测试。 您可以实例化要测试的对象,并为其所有依赖项提供模拟对象,但当它作为组合应用程序运行时,组合过程会自动将所有实际对象挂钩在一起。

我想提到的最重要的一点是,尽管System.Addins已经在框架中,但是我没有看到有很多人使用它的证据,但是MEF只是坐在CodePlex上被认为包含在.NET 4,人们已经开始用它来构建大量的应用程序(包括我自己)。 我想这个告诉你一些关于这两个框架的东西。

开发并交付了MAF应用程序。 我对MAF的看法有点疲惫。

MAF在最坏的情况下是一个“去耦合”系统或“松散耦合”系统。 MEF最好是“耦合”系统或“松散耦合”系统。

我们使用MAF实现的MAF好处是:

  1. 在应用程序运行时安装新的或更新现有的组件。 AddIn可以在应用程序运行时进行更新,并且无缝地向用户显示更新。 你必须有AppDomains的。

  2. 基于购买组件的授权。 我们可以控制哪个AddIn由用户的角色和权限加载,以及AddIn是否被许可使用。

  3. 快速发展(更快的上市时间)。 AddIn开发与Agile方法非常吻合,开发团队每次开发一个AddIn,而不必与其他应用程序一起开发集成件。

  4. 改进的QA(一次只QA一个组件)。 然后QA可以测试和发布一个功能的缺陷。 测试案例更容易开发和实施。

  5. 部署(添加组件,因为他们正在开发和发布,他们“只是工作”)。 部署只是制作AddIn并安装文件的问题。 没有其他考虑是必要的!

  6. 新组件使用旧组件。 在早期开发的AddIn继续工作。 新的AddIns无缝地融入到应用程序中

在我看来,这两种技术实际上针对的是非常不同的用例。

在纯粹的依赖注入场景中,MEF通常是最好的,其中提供最终集成解决方案的个人或团队正在组装一切并为整体完整性提供保证,但需要具有关键功能的不同实现。

MAF适用于某人/小组正在开发平台或主机的情况,其他小组将在事实之后以不受主机组控制的方式添加功能。 在这种情况下,需要更复杂的机制来“保护”主机免受恶意加载项(或相互保护加载项)的影响。

第三种类似模式技术是整个ProviderBase方案。 这也可以替换一个功能,但是它的目标实际上是主机/应用程序绝对需要一个功能的场景,而且真的需要通过配置指定不同的实现。

我刚刚发现这篇冗长的文章讨论MAF和MEF。 http://emcpadden.wordpress.com/2008/12/07/managed-extensibility-framework-and-others/

除了其他答案所提出的观点之外,听起来好像MEF和MAF之间的一个主要区别是,托管扩展性框架将允许一个可组合部分依赖另一个。 例如,它会让一个插件依赖于另一个插件。

Managed Extensibility Framework也不会像System.AddIn那样区分主机和加载项。 就MEF而言,它们都只是可组合的部分。

在我看来,发现差异的最好方法是一些实际操作的代码。 我发现了两个MSDN演练,都带有一个计算器示例,因此您可以轻松比较它们的实现:

MEF: 使用MEF部件的简单计算器示例
M eaged E xtensibility F ramework)

  • 演示如何使用MEF技术构建简单的计算器。 不显示如何加载外部dll。 (但你可以通过使用catalog.Catalogs.Add(new DirectoryCatalog("Plugins", "*.dll"));来简单地修改示例catalog.Catalogs.Add(new DirectoryCatalog("Plugins", "*.dll"));而不是使用catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));并提取计算器代码和合同来分离DLL项目。)
  • MEF不需要具有特定的目录结构,即使对于小型项目,使用也很简单直接。 它使用属性来声明导出的内容,这很容易阅读和理解。 例如: [Export(typeof(IOperation))] [ExportMetadata("Symbol", '+')] class Add: IOperation { public int Operate(int left, int right) { return left + right; } } [Export(typeof(IOperation))] [ExportMetadata("Symbol", '+')] class Add: IOperation { public int Operate(int left, int right) { return left + right; } }

  • MEF不会自动处理版本控制

MAF: 简单的计算器,带有V1和V2版本的MAF插件
M anaged A ddin F ramework)

  • 演示如何使用V1插件构建计算器,然后如何在保持向后兼容性的同时移至V2插件( 注意:您可以在此处找到插件的V2版本,原始文章中的链接被破坏)
  • MAF 强制执行一个特定的目录结构,它需要大量的样板代码才能使其工作,因此我不推荐将它用于小型项目。 例:
     Pipeline AddIns CalcV1 CalcV2 AddInSideAdapters AddInViews Contracts HostSideAdapters 

MEF和MAF都包含在.NET Framework 4.x中。 如果你比较两个例子,你会发现MAF插件比MEF框架复杂得多,所以你需要仔细考虑何时使用这些框架。

MAF和MEF都可以使用AppDomain,并且都可以在运行时加载/卸载dll。 然而,我发现的差异是:MAF AddIns是解耦的,MEF组件是松耦合的; MAF“激活”(新实例),而MEF在默认情况下创建实例。

使用MEF,您可以使用泛型为任何合同制作GenericHost。 这意味着MEF加载/卸载和组件管理可以在一个共同的库中并且一般使用。