托管可扩展性框架(MEF)和托管AddIn框架(MAF,又称System.AddIn)似乎完成非常相似的任务。根据这个Stack Overflow问题(Is MEF a replacement for System.Addin?),你甚至可以同时使用两者。
何时选择使用一个而不是另一个?在什么情况下会选择同时使用两个?
托管可扩展性框架(MEF)和托管AddIn框架(MAF,又称System.AddIn)似乎完成非常相似的任务。根据这个Stack Overflow问题(Is MEF a replacement for System.Addin?),你甚至可以同时使用两者。
何时选择使用一个而不是另一个?在什么情况下会选择同时使用两个?
我已经评估了这些选项,以下是我的结论。
MAF是一个真正的插件框架。你可以将插件完全分离,甚至在一个单独的应用程序域内运行它们,这样如果插件崩溃,它也不会使你的应用程序崩溃。它还提供了一种非常完整的方法,通过依赖给定的合同来解耦插件。事实上,你可以版本化你的合同适配器,为旧的插件提供向后兼容性,同时升级主应用程序。虽然这听起来很好,但你必须付出沉重的代价才能跨应用程序域。你不仅要付出速度方面的代价,还要付出你可以来回发送的类型灵活性方面的代价。
MEF更像是带有一些附加优势(如可发现性和...(对此我没有想法))的依赖注入。MAF具有的隔离程度在MEF中并不存在。它们是两个不同的框架,针对两个不同的问题。
Danielg说的很好。我想补充一下:
如果您观看System.Addins的视频,会发现他们明显在谈论非常大的项目。他谈到一个团队管理主机应用程序,另一个团队管理每个AddIn,第三个团队管理合同和管道。基于此,我认为System.Addins显然适用于更大型的应用程序。我考虑的是像SAP这样的ERP系统(也许不是那么大,但您可以理解这个想法)。如果您观看了那些视频,您会发现使用System.Addins的工作量非常大。如果您有很多公司为您的系统编写第三方插件,并且不能违反任何这些插件合同,则它将有效。
另一方面,MEF似乎与SharpDevelop的插件方案、Eclipse插件架构或Mono.Addins更相似。比起System.Addins,它更容易理解,并且我认为它更加灵活。您失去的东西是,您不能使用MEF获得AppDomain隔离或强版本合同。 MEF的优点是,您可以将整个应用程序结构化为部分组成,因此您可以针对不同的客户以不同的配置来发布产品,如果客户购买了新功能,您只需将该功能的部件放入其安装目录中,应用程序就会看到它并运行。它还有助于测试。您可以实例化要测试的对象,并为其所有依赖项提供模拟对象,但是当作为组合应用程序运行时,组合过程会自动将所有真实对象连接在一起。
我想提出的最重要的一点是,即使System.Addins已经是框架的一部分,但我没有看到很多人使用它,但是MEF只是坐在CodePlex上,据说将包含在.NET 4中,而人们已经开始使用它来构建大量应用程序(包括我自己)。我认为这告诉您一些关于这两个框架的事情。
我曾经开发并发布过一个MAF应用,因此我的MAF观点有些偏见。
MAF是一个“解耦合”系统或者最差的情况下是“松耦合”系统。而MEF则是一个“耦合”系统或者最好的情况下是“松耦合”系统。
使用MAF所获得的好处有:
在应用程序运行中安装新组件或更新现有组件。AddIn可以在应用程序运行时进行更新,更新对用户来说是无缝的。这需要AppDomains的支持。
基于购买的组件进行许可控制。我们可以根据用户的角色和权限以及AddIn是否获得许可来控制加载哪些AddIn。
快速开发(更快的上市时间)。AddIn开发与敏捷方法学非常匹配,开发团队一次只开发一个AddIn,而不必同时开发与应用程序的集成部分。
改进的QA(仅测试单个组件)。然后QA可以测试和报告单个功能位的缺陷。测试用例更易于开发和实施。
部署(随着开发和发布加入组件,它们“只需工作”)。部署只涉及创建AddIn并安装文件。不需要考虑其他因素!
新组件与旧组件兼容。早期开发的AddIn仍然可以正常工作。新的AddIn可以无缝地融入应用程序中。
在我看来,这两种技术实际上面向完全不同的应用场景。
MEF通常在纯依赖注入的场景下表现最佳,其中交付最终集成解决方案的人或团队正在组装一切并为整体完整性提供担保,但需要具有关键功能的不同实现。
MAF适用于一个场景,即某些人或团队正在开发平台或主机,其他团队将在事后以不在主机团队控制范围内的方式添加功能。在这种情况下,需要更复杂的机制来“保护”主机免受流氓插件的影响(或者保护插件彼此之间的影响)。
第三个类似模式的技术是整个ProviderBase方案。这也使替换功能成为可能,但它的目标实际上是主机/应用程序绝对需要某种能力,而需求实际上是通过配置指定不同的实现。
我认为最好的发现差异的方法是亲手写一些代码。我找到了两个MSDN演示文稿,都有一个计算器示例,这样你可以轻松比较它们的实现:
MEF: 使用MEF部件的简单计算器示例
(Managed Extensibility Framework)
catalog.Catalogs.Add(new DirectoryCatalog("Plugins", "*.dll"));
而不是使用catalog.Catalogs.Add(new
AssemblyCatalog(typeof(Program).Assembly));
以及将计算器代码和契约提取到单独的DLL项目中,来修改示例。)
[Export(typeof(IOperation))]
[ExportMetadata("Symbol", '+')]
class Add: IOperation
{
public int Operate(int left, int right)
{
return left + right;
}
}
MEF不会自动处理版本控制。
MAF: 带有 V1 和 V2 版本MAF 插件的简单计算器
(Managed Addin Framework)
Pipeline AddIns CalcV1 CalcV2 AddInSideAdapters AddInViews Contracts HostSideAdapters
MEF和MAF都包含在.NET Framework 4.x中。如果你比较这两个例子,你会注意到MAF插件比MEF框架更加复杂 - 所以在使用这些框架时需要仔细考虑。
MAF 和 MEF 都可以使用 AppDomains 并且都能在运行时加载/卸载 dll。然而,我发现它们之间的区别是:MAF AddIns 是解耦的,MEF 组件是松耦合的;MAF "激活"(新实例),而 MEF 默认通过实例化来创建。
使用 MEF,您可以使用泛型为任何契约制作 GenericHost。这意味着 MEF 的加载/卸载和组件管理可以在一个通用库中使用泛型。