.NET 4.0 MEF FAQ (Socket, 插件和扩展)






4.92/5 (73投票s)
.NET 4.0 MEF FAQ (Socket, 插件和扩展)
视频更新....
本视频介绍了.NET 4.0 的一个功能,称为 MEF(托管扩展性框架)。
目录
- 引言和目标
- 什么是 MEF(托管扩展性框架)?
- 如何在 .NET 4.0 中实现 MEF?
- 能否结合以上三个步骤,看一个简单的 MEF 示例?
- Import 和 Export 的数据类型是否必须匹配?
- 能否通过某个定义的契约而不是 .NET 数据类型来连接 Import 和 Export?
- 这看起来与 DI 和 IOC 非常相似,为什么还要重复发明?
- 它们可以协同工作吗?
- 我们想看一个 Silverlight 的示例?
- 能否也看一个 WPF 的简单示例?
- ASP.NET 的示例怎么样?
- 源代码
- 参考
引言和目标
本 FAQ 深入探讨了 .NET 4.0 MEF 的基础知识(Import 和 Export),并解释了何时使用 MEF 而不是 DI/IOC。本文还逐步介绍了如何在 Silverlight、WPF 和 ASP.NET 等各种技术中使用 MEF。
请随时下载我免费的 .NET 电子书,其中包含 WCF、WPF、WWF、Silverlight 等 400 个问答,在此处下载。
什么是 MEF(托管扩展性框架)?
MEF 是一个可以使您的应用程序可扩展的框架。例如,您有一个会计应用程序,并且希望提供一个挂钩(socket),外部供应商可以连接(plug)到该挂钩并为会计应用程序添加发票功能。
例如,您有一个应用程序,希望不同的供应商通过自己的功能与之连接并扩展您的应用程序。
因此,供应商只需将组件放入应用程序中,应用程序就会发现它们并进行连接和扩展。
如何在 .NET 4.0 中实现 MEF?
实现 MEF 是一个三步过程:
• Import(创建 socket):使用“Import
”属性在您的应用程序中定义一个挂钩或 socket。
• Export(连接插件):使用“Export
”属性创建可以连接到插件或挂钩的插件。
• Compose(进行扩展):使用组合容器并进行组合。
能否结合以上三个步骤,看一个简单的 MEF 示例?
我们将创建一个简单的类,该类将有一个挂钩来导入 string
消息。换句话说,任何具有 string
消息实现功能的类都可以连接到该挂钩并扩展该类。
第一步:创建 Socket(Import)
第一步是创建一个占位符/挂钩/socket,其他组件可以插入其中。
导入 MEF 所需的以下命名空间。
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
为了定义一个挂钩,我们创建了一个名为“ImportMessage
”的空属性,并为其添加了“Import
”属性。
class Program
{
[Import()]
public string ImportMessage
{
set;
get;
}
}
上面的“import
”属性表示任何拥有 string
功能实现类型的类都可以连接到我并附加该功能。
第二步:创建并连接插件(Export)
为了创建插件或扩展,我们需要使用如下所示的“Export”属性。在当前场景下,此属性不执行任何操作,只是显示一个简单的 string
。
class clsMySimpleMessage
{
[Export()]
string ExportMessage
{
set
{
}
get
{
return "Message inserted via MEF";
}
}
}
第三步:连接并扩展(Compose)
好的,我们已经创建了 socket 和插件,现在是时候将它们连接起来了。以下是相关的代码:
private void Compose()
{
// Get a reference to the current assemblies in the project.
AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
// Once you have got the reference of catalog add it to the composition container.
CompositionContainer compositionContainer = new CompositionContainer(catalog);
// Finally call composeparts to connect the Import with Export.
compositionContainer.ComposeParts(this);
// use the property
Console.WriteLine(ImportMessage);
Console.ReadLine();
}
换句话说,Export、Import 和 Compose。下图对此进行了总结。
“Export
”就像您提供的东西,而“import
”就像您接收的东西。
Import 和 Export 的数据类型是否必须匹配?
Import 和 Export 的类型必须匹配,否则在组合时会收到如下所示的错误。不兼容的 socket 和插件能连接吗?
能否通过某个定义的契约而不是 .NET 数据类型来连接 Import 和 Export?
在现实世界中,您的挂钩应该是像客户、供应商等实际的契约类型,而不是像 string
、int
、Boolean
等简单的 .NET 数据类型。为了在 MEF 中创建现实世界的挂钩,我们首先需要使用接口创建契约,如下所示:
interface ImyInterface
{
string getString();
}
我们需要确保 import
和 export
属性中定义的挂钩是相同的接口类型,如下所示。使用组合容器的绑定逻辑没有改变;与上一节的描述相同。
[Export(typeof(ImyInterface))]
class clsMyImplementation : ImyInterface
{
public string getString()
{
return "This is my string";
}
}
class Program
{
[Import()]
public ImyInterface myInterface
{
set;
get;
}
}
这看起来与 DI 和 IOC 非常相似,为什么还要重复发明?
如果您不熟悉 DI/IOC,请在此处阅读。
它们在很大程度上是重叠的,但目标不同。DI 和 IOC 用于解耦,而 MEF 用于可扩展性。以下需求将更详细地说明如何选择解决方案:
要求 | 解决方案 |
应用程序应为分层应用程序,每个层都与其他层解耦,以实现更好的可重用性和可维护性。 | DI IOC |
应用程序应提供将数据导出为不同格式的功能。外部供应商应能够插入自己的导出机制到应用程序中。 | MEF |
下表对此进行了详细总结:
DI / IOC | MEF | |
解耦 | 是 | |
可扩展性 | 是 | |
集成已知项 | 是 | |
集成未知项 | 是 | |
自动发现 | 是 | |
注册 | 是 | |
发现 | 是 | |
编译时 | 是 | |
运行时 | 是 |
如果您仍有疑问,请在此处联系 Glenn Block。
它们可以协同工作吗?
假设您有一个应用程序,并且有以下需求:
要求 | 解决方案 |
应用程序应为三层架构,UI、BO 和 DAL 层彼此解耦。 | DI IOC |
数据访问层需要开放且可扩展。应用程序将允许供应商插入自己的数据连接机制,以便应用程序可以连接到他们的专有数据库。 | MEF |
处理第一个需求的方法是使用您喜欢的 IOC 容器,而第二个需求就是 MEF 发挥作用的地方。下图展示了它们如何在整个体系中发挥作用。
在两者之间做出选择时,最终目标更为重要。
尼古拉斯·布鲁姆哈特(Mr. Nicholas Blumhardt)的这篇精彩文章展示了 MEF 和 IOC 如何协同工作。
我们想看一个 Silverlight 的示例?
主要重要步骤不变。
第一步:创建 Socket(Import)
定义您想要导入的 Silverlight 项。在下面的代码片段中,我们定义了一个用户控件类型的集合。
public partial class MainPage : UserControl
{
[ImportMany]
public ObservableCollection<UserControl> ImportedItems
{ get; set; }
}
第二步:创建并连接插件(Export)
使用“Export”来定义插件。对于当前场景,我们定义了两个 Silverlight 用户控件,并使用 export 属性公开“UserControl
”作为类型。
[Export(typeof(UserControl))]
public partial class SilverlightControl1 : UserControl
{
public SilverlightControl1()
{
InitializeComponent();
}
}
[Export(typeof(UserControl))]
public partial class SilverlightControl2 : UserControl
{
public SilverlightControl2()
{
InitializeComponent();
}
}
第三步:连接并扩展(Compose)
使用“SatisfyImport
”来组合 exports 和 imports。
CompositionInitializer.SatisfyImports(this);
如果运行它,您应该会在主 Silverlight UI 容器中看到组合的用户控件,如下所示:
整个 Silverlight 的图景如下所示:
能否也看一个 WPF 的简单示例?
呼……累了,稍后更新。
ASP.NET 的示例怎么样?
呼……累了,稍后更新。
源代码
您可以从本文顶部的链接下载源代码。
参考
- Hansel 和 Glenn 在 http://www.hanselminutes.com/default.aspx?showID=166 讨论了 MEF 和 IOC 之间的区别。
- 10 个使用 MEF 的理由
http://csharperimage.jeremylikness.com/2010/04/ten-reasons-to-use-managed.html - MEF 入门
- http://blogs.microsoft.co.il/blogs/bnaya/archive/2009/11/28/mef-for-beginner-concept-part-1.aspx
- 正如 Sreeni Ramadurai 所说,它是 import、export 和 bind。
http://mstecharchitect.blogspot.com/2010/02/mef-managed-extensibility-framework.html - 关于 MEF 的简单文章
- http://www.sidarok.com/web/blog/content/2008/09/26/what-is-this-managed-extensibility-framework-thing-all-about.html
如需进一步阅读,请观看以下面试准备视频和分步视频系列。