zoukankan      html  css  js  c++  java
  • 使用MEF实现IOC

    使用MEF实现IOC

    〇、目录

    一、前言

      (一)什么是IOC

      (二)什么是MEF

      (三)为什么选择MEF

    二、准备工作

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

    四、MEF在MVC中的使用

    五、总结

    六、源码下载

    一、前言

    (一)什么是IOC

      什么是IOC?基本含义是:当某个角色(调用者)需要另一个角色(被调用者)的协助时,在传统程序设计过程中,通常由调用者来创建被调用者的实例。但在加入IOC组件后,创建被调用者实例的工作不再由调用者来完成,而是将由IOC组件来自动完成,然后注入调用者。

      网上已经非常非常多的介绍资料了,这里就不赘述了,这里给出几篇参考:

    1. 百度百科:控制反转
    2. 依赖注入(IOC)

    (二)什么是MEF

    Managed Extensibility Framework 或 MEF 是一个用于创建可扩展的轻型应用程序的库。 应用程序开发人员可利用该库发现并使用扩展,而无需进行配置。 扩展开发人员还可以利用该库轻松地封装代码,避免生成脆弱的硬依赖项。 通过 MEF,不仅可以在应用程序内重用扩展,还可以在应用程序之间重用扩展。

       

      下面这篇文章对MEF的介绍非常到位:

    1. Managed Extensibility Framework概述
    2. 体验Managed Extensibility Framework精妙的设计

    (三)为什么选择MEF

      已经有很多很好的诸如Unity,Autofac,Ninject,Spring.Net等等IOC组件了,为什么我还要推荐使用MEF呢,下面是我推荐的理由:

    1. .net4.0自带,非第三方组件
    2. 0配置,没有像其他IOC组件那样需要复杂的外部配置支持
    3. 使用非常简单的方式来提供具有强大灵活性的可扩展性支持

    二、准备工作

      本文案例很简单,一个接口

      这个接口的实例类

      我们要做的工作就是要通过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架构设计
  • 相关阅读:
    unix网络编程 初步了解TCP/IP协议
    unix网络编程 常见概念
    linux 环境变量
    linux c编程
    第二周学习笔记
    jmeter第一周学习笔记
    建造者模式
    原型设计模式
    抽象工厂模式
    工厂方法模式
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2960742.html
Copyright © 2011-2022 走看看