使用MEF实现IOC
使用MEF实现IOC
〇、目录
一、 前言
(一) 什么是IOC
(二) 什么是MEF
(三) 为什么选择MEF
二、 准备工作
三、 MEF在桌面程序中的使用
四、 MEF在MVC中的使用
五、 总结
六、 源码下载
一、前言 (一)什么是IOC
什么是IOC?基本含义是:当某个角色(调用者)需要另一个角色(被调用者)的协助时,在传统程序设计过程中,通常由调用者来创建被调用者的实例。但在加入IOC组件后,创建被调用者实例的工作不再由调用者来完成,而是将由IOC组件来自动完成,然后注入调用者。
网上已经非常非常多的介绍资料了,这里就不赘述了,这里给出几篇参考:
百度百科:控制反转 依赖注入(IOC) (二)什么是MEF
Managed Extensibility Framework 或 MEF 是一个用于创建可扩展的轻型应用程序的库。 应用程序开发人员可利用该库发现并使用扩展,而无需进行配置。 扩展开发人员还可以利用该库轻松地封装代码,避免生成脆弱的硬依赖项。 通过 MEF,不仅可以在应用程序内重用扩展,还可以在应用程序之间重用扩展。
下面这篇文章对MEF的介绍非常到位:
Managed Extensibility Framework概述 体验Managed Extensibility Framework精妙的设计 (三)为什么选择MEF已经有很多很好的诸如Unity,Autofac,Ninject,Spring.Net等等IOC组件了,为什么我还要推荐使用MEF呢,下面是我推荐的理由:
.net4.0自带,非第三方组件 0配置,没有像其他IOC组件那样需要复杂的外部配置支持 使用非常简单的方式来提供具有强大灵活性的可扩展性支持二、准备工作
本文案例很简单,一个接口
这个接口的实例类
我们要做的工作就是要通过MEF来解除业务使用者对具体业务实现的依赖关系。
要使用MEF,需添加 System.ComponentModel.Composition 类库的引用
与其他通过外部配置文件来完成接口与实现类的对应关系的IOC组件不同,MEF是通过 ExportAttribute 特性来完成的(如有多个实现,可加入别名来区分),如下图所示:
三、MEF在桌面程序中的使用
在桌面程序中,需要完成两个部分的目录匹配,一个是dll中的匹配,另一个为exe程序集中的匹配,分别使用到DirectoryCatalog与AssemblyCatalog两个目录类。而两个目录类需加入到 AggregateCatalog 目录类中,才能参与组合容器CompositionContainer的初始化。
在调用方,只需要使用 ImportAttribute 特性来注入即可获得被调用者的实例
由于这里调用方法是静态方法,手动从组合容器中获取 调用者HomeBusiness类的实例
输出,得到了业务实现类 HomeService返回的结果
四、MEF在MVC中的使用
在MVC的项目中,IOC组件是通过 DependencyResolver类中的 SetResolver(IDependencyResolver resolver) 方法来向MVC提供注册点的,所以我们只需要实现一个 IDependencyResolver 接口的MEF实现类,即可完成MEF在MVC中的注册工作。
另外考虑到Web应用程序的无状态性,即每次访问都是独立进行的,所以IOC组件产生的对象实例也必须唯一,否则不同用户的操作就可能串线,产生相互干扰。在这里,我们使用HttpContext.Current.Items集合来保存 组合容器CompositionContainer的实例,以使每个用户的数据保持独立,并且同一用户的同一个Http请求中使用同一对象实例。
MefDependencySolver实现代码如下:
1 namespace Liuliu.Demo.Site.Web.Helper.Ioc
2 {
3 public class MefDependencySolver : IDependencyResolver
4 {
5 private readonly ComposablePartCatalog _catalog;
6 private readonly string _httpContextKey = Guid.NewGuid().ToString();
7
8 public MefDependencySolver(ComposablePartCatalog catalog)
9 {
10 _catalog = catalog;
11 }
12
13 public CompositionContainer Container
14 {
15 get
16 {
17 if (! HttpContext.Current.Items.Contains(_httpContextKey))
18 {
19 HttpContext.Current.Items.Add(_httpContextKey, new CompositionContainer(_catalog));
20 }
21 CompositionContainer container = (CompositionContainer)HttpContext.Current.Items[_httpContextKey];
22 HttpContext.Current.Application[ " Container " ] = container;
23 return container;
24 }
25 }
26
27 #region IDependencyResolver Members
28
29 public object GetService(Type serviceType)
30 {
31 string contractName = AttributedModelServices.GetContractName(serviceType);
32 return Container.GetExportedValueOrDefault< object > (contractName);
33 }
34
35 public IEnumerable< object > GetServices(Type serviceType)
36 {
37 return Container.GetExportedValues< object > (serviceType.FullName);
38 }
39
40 #endregion
41 }
42 }
在Global.asax.cs的Application_Start方法中初始化MEF容器,由于Web应用程序中只需要在DLL中查找匹配,所以只使用DirectoryCatalog即可。
作为调用者,Controller中同样需要添加被调用者的注入信息
1 namespace Liuliu.Demo.Site.Web.Controllers
2 {
3 [Export]
4 public class HomeController : Controller
5 {
6 [Import]
7 public IHomeContract HomeContract { get ; set ; }
8
9 public ActionResult Index()
10 {
11 string data = HomeContract.GetData();
12 return Content(data);
13 }
14 }
15 }
执行程序,同样输出了HomeService的返回数据:
五、总结
MEF不同于 显式注册可用组件的做法 ,在MEF中组件被视为部件。这些部件主要有“导入”(Import)部件和“导出”(Export)部件,此外MEF提供了一个组合容器(ComposeContainer),容器会发现指定Catalog的导入导出部件,并按Contract(协定)、Metadata(元数据)等对导入和导出部件进行组合。
上述文字已经把MEF中涉及的相关概念指出了,下面具体说明一下:
Export(导出): “Export”也就是我们常说的组件或者模块或者服务,它是部件向容器中的其他部件提供的一个值、功能或服务等;
Import(导入): "Import”,既扩展点,是组件,服务等接入系统的窗口 , 是部件向要通过可用导出满足的容器提出的要求, MEF 支持若干导入类型,其中包括动态导入、延迟导入、必备导入和可选导入 ;
Contract(协定): 是Export和Import的一种约定,一种协议, 只有Contract相匹配的Import和Export部件才能组装成功;
Catalog(目录): 为了发现可用于组合容器的部件,组合容器将使用“Catalog”。 目录是一个对象,通过它发现可用部件, MEF 提供了用于从提供的类型、程序集或磁盘路径创建Catalog。
Compose(组合):在MEF中,容器将导入与导出匹配的这一过程我们称之为组合, 部件由 MEF 组合,MEF 将部件实例化,然后使导出程序与导入程序相匹配。
六、源码下载
LiuliuFrameworkDemo01_MEF.rar
分类: MVC , 架构设计
标签: MVC , 架构设计
作者: Leo_wl
出处: http://HdhCmsTestcnblogs测试数据/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息