MVC实用架构设计:使用MEF应用IOC(依赖倒置)

一、前言

临河网站制作公司哪家好,找成都创新互联公司!从网页设计、网站建设、微信开发、APP开发、响应式网站设计等网站项目制作,到程序开发,运营维护。成都创新互联公司自2013年起到现在10年的时间,我们拥有了丰富的建站经验和运维经验,来保证我们的工作的顺利进行。专注于网站建设就选成都创新互联公司

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

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

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

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

二、MEF的优势

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

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

  1. .net4.0 自带:MEF的功能在 System.ComponentModel.Composition.dll 程序集中,直接引用即可使用,不用安装第三方组件
  2. 0 配置:MEF是不需要使用配置文件或代码对接口与实现进行一一配对的,只需要简单的使用几个Attribute特性,就能自动完成源与目标的配对工作
  3. 自动化:系统初始化时自动遍历程序目录或指定文件夹下的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. ///   
  2.     /// MEF依赖关系解析类  
  3.     ///   
  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(contractName);  
  34.         }  
  35.  
  36.         public IEnumerable GetServices(Type serviceType)  
  37.         {  
  38.             return Container.GetExportedValues(serviceType.FullName);  
  39.         }  
  40.  
  41.         #endregion  
  42.     } 
  43. #p#

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

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

    在加入了IOC组件之后,我们的架构就变成了面向接口编程的架构了,上层代码仅依赖于下层的接口,而不依赖于下层的具体实现,为了防止站点业务层的实现代码中出现如下所示的代码:

     

     
     
     
     
    1. IAccountSiteContract accountContract = new AccountSiteService(); 

    上一篇文章中也提到过,需要把站点业务层中的实现类的可访问性由 public 修改为 Internal,以实现上层代码对下层代码的真正隔离。

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

    ***,给个温馨提示:

    MEF的导出导入是整体关联的,只要树中某一个部件匹配失败,整个树将无法实例化,也就是会出现Import的属性值为null的情况,这种情况下,可以使用MEF开发团队提供的调试工具MEFX来进行问题的快速定位。具体使用方法参考如下:

    • 结构分析工具 (Mefx)
    • 调试 MEF

    五、源码获取

    GMFrameworkForBlog2.zip

    为了让大家能***时间获取到本架构的***代码,也为了方便我对代码的管理,本系列的源码已加入微软的开源项目网站 http://www.codeplex.com,地址为:

    https://gmframework.codeplex.com/

    可以通过下列途径获取到***代码:

    • 如果你是本项目的参与者,可以通过VS自带的团队TFS直接连接到 https://tfs.codeplex.com:443/tfs/TFS17 获取***代码
    • 如果你安装有SVN客户端(亲测TortoiseSVN 1.6.7可用),可以连接到 https://gmframework.svn.codeplex.com/svn 获取***代码
    • 如果以上条件都不满足,你可以进入页面 https://gmframework.codeplex.com/SourceControl/latest 查看***代码,也可以点击页面上的 Download 链接进行压缩包的下载,你还可以点击页面上的 History 链接获取到历史版本的源代码
    • 如果你想和大家一起学习MVC,学习EF,欢迎加入Q群:5008599(群发言仅限技术讨论,拒绝闲聊,拒绝酱油,拒绝广告)
    • 如果你想与我共同来完成这个开源项目,可以随时联系我。

    网站标题:MVC实用架构设计:使用MEF应用IOC(依赖倒置)
    URL网址:http://www.shufengxianlan.com/qtweb/news23/480823.html

    网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

    广告

    声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联