好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

使用MEF实用IOC(依赖倒置)

使用MEF实用IOC(依赖倒置)

使用MEF实用IOC(依赖倒置)

〇、目录

一、 前言

二、 MEF的优势

三、 MEF在桌面程序中的使用

四、 在MVC中使用MEF

五、 源码下载

六、 系列导航

一、前言

  在《 上篇 》中,基本的项目结构已经搭建起来了,但是有个问题,层与层之间虽然使用了接口进行隔离,但实例化接口的时候,还引入了接口实现类的依赖。如下图:

   面向接口编程 ,Controller应该只依赖于站点业务层的接口,而不能依赖于具体的实现,否则,就违背了在层之间设置接口的初衷了。

  另外,如果上层只依赖于下层的接口,在做单元测试的时候,就可以用 Moq , Fakes 等Mock工具来按实际需求来模拟接口的实现,就可以灵活的控制接口的返回值来对各种情况进行测试,如果依赖于具体的实现,项目的可测试性将大大减小,不利于进行自动化的单元测试。

  要不依赖于具体的实现,就不能使用通常的 T t = new T() 的方式来获得一个类的实例了,需要通过IOC容器来对对象生命周期,依赖关系等进行统一的管理。

二、MEF的优势

  .net中可用的IOC容器非常多,如 CastleWindsor,Unity,Autofac,ObjectBuilder,StructureMap,Spring.Net等,这些第三方工具各不相同,但功能大体都相同,大都需要事先对接口与实现进行配对(通过代码或配置文件),然后由系统自动或手动来通过接口来获得相应实现类的实例,对象实例化的工作由IOC容器自动完成。

  MEF相对于上面的这些IOC容器有什么优势呢?下面是我推荐的理由:

.net4.0 自带:MEF的功能在 System.ComponentModel.Composition.dll 程序集中,直接引用即可使用,不用安装第三方组件 0 配置:MEF是不需要使用配置文件或代码对接口与实现进行一一配对的,只需要简单的使用几个Attribute特性,就能自动完成源与目标的配对工作 自动化:系统初始化时自动遍历程序目录或指定文件夹下的dll,根据程序集中接口与类的特定Attribute特性进行自动配对。

三、MEF在桌面程序中的使用

  在桌面程序中,需要完成两个部分的目录匹配,一个是dll中的匹配,另一个为exe程序集中的匹配,分别使用到DirectoryCatalog与AssemblyCatalog两个目录类。而两个目录类需加入到 AggregateCatalog 目录类中,才能参与组合容器CompositionContainer的初始化。

  在服务提供方的实现类中,使用  ExportAttribute  标记要与之匹配的接口,如下图所示。在服务调用方,使用  ImportAttribute  来给接口注入实现类的实例,如上图所示。

  由于调用方法为静态的方法,Program类的实例仍需手动从组件容器中获得,然后尝试登录:

  输出结果,接口AccountContract并没有赋值,但能输出其实现类的信息,同时登录也能成功调用:

四、MEF在MVC中的使用

  在MVC的项目中,IOC组件是通过 DependencyResolver类中的 SetResolver(IDependencyResolver resolver) 方法来向MVC提供注册点的,所以我们只需要实现一个 IDependencyResolver 接口的MEF实现类,即可完成MEF在MVC中的注册工作。

  另外考虑到Web应用程序的无状态性,即每次访问都是独立进行的,所以IOC组件产生的对象实例也必须唯一,否则不同用户的操作就可能串线,产生相互干扰。在这里,我们使用HttpContext.Current.Items集合来保存 组合容器CompositionContainer的实例,以使每个用户的数据保持独立,并且同一用户的同一个Http请求中使用同一对象实例。另外考虑到可能会有某种情况下需要手动获取组合容器中的实例,把组合容器缓存到了当前上下文中的Application中。

  MefDependencySolver实现代码如下: 

  1       ///   <summary> 
  2       ///   MEF依赖关系解析类
   3       ///   </summary> 
  4       public   class   MefDependencySolver : IDependencyResolver
   5       {
   6           private   readonly   ComposablePartCatalog _catalog;
   7           private   const   string  HttpContextKey =  "  MefContainerKey  "  ;
   8  
  9           public   MefDependencySolver(ComposablePartCatalog catalog)
  10           {
  11              _catalog =  catalog;
  12           }
  13  
 14           public   CompositionContainer Container
  15           {
  16               get 
 17               {
  18                   if  (! HttpContext.Current.Items.Contains(HttpContextKey))
  19                   {
  20                      HttpContext.Current.Items.Add(HttpContextKey,  new   CompositionContainer(_catalog));
  21                   }
  22                  CompositionContainer container =  (CompositionContainer)HttpContext.Current.Items[HttpContextKey];
  23                  HttpContext.Current.Application[ "  Container  " ] =  container;
  24                   return   container;
  25               }
  26           }
  27  
 28           #region  IDependencyResolver Members
 29  
 30           public   object   GetService(Type serviceType)
  31           {
  32               string  contractName =  AttributedModelServices.GetContractName(serviceType);
  33               return  Container.GetExportedValueOrDefault< object > (contractName);
  34           }
  35  
 36           public  IEnumerable< object >  GetServices(Type serviceType)
  37           {
  38               return  Container.GetExportedValues< object > (serviceType.FullName);
  39           }
  40  
 41           #endregion 
 42      }

    在Global.asax.cs的Application_Start方法中初始化MEF容器,由于Web应用程序中只需要在DLL中查找匹配,所以只使用DirectoryCatalog即可。

   在AccountController类中加入MEF的Attribute标签,并删除原来构造函数中的AccountContract属性的赋值代码

其他代码不变,运行网站,同样能正常调用登录功能

五、源码下载

  GMFrameworkForBlog2.zip

系列导航 MVC实用架构设计(〇)—— 总体设计 MVC实用架构设计(一)—— 项目结构搭建 MVC实用架构设计(二)——使用MEF实用IOC MVC实用架构设计(三)——EntityFramework-Code First(1):UnitOfWork MVC实用架构设计(三)——EntityFramework-Code First(2):Repository MVC实用架构设计(三)——EntityFramework-Code First(3):实体关系 MVC实用架构设计(三)——EntityFramework-Code First(4):实体仓储 MVC实用架构设计(三)——EntityFramework-Code First(5):使用T4模板生成代码 MVC实用架构设计(三)——EntityFramework-Code First(6):数据查询 MVC实用架构设计(三)——EntityFramework-Code First(7):二级缓存 MVC实体架构设计(四)——日志记录 未完待续。。。

作者 :郭明锋
出处 : http://www.cnblogs.com/guomingfeng

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

 

分类:  MVC ,  架构设计

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于使用MEF实用IOC(依赖倒置)的详细内容...

  阅读:104次