IOC之MEF学习
MEF原理上很简单,找出有共同接口的导入、导出。然后找到把导出的实例化,赋给导入。说到底MEF就是找到合适的类实例化,把它交给导入。
Export 特性可修饰类、字段、属性或方法,而 Import 特性可修饰字段、属性或构造函数参数。为了使导入与导出匹配,导入和导出必须具有相同的协定。
假设有一个类MyClass,它声明了可以导入插件的类型是IMyAddin。
public class MyClass
{
[Import]
public IMyAddin MyAddin { get; set; }
}
这里有一个类,它声明为导出。类型同样为IMyAddin。
[Export(typeof(IMyAddin))]
public class MyLogger : IMyAddin { }
这样我们使用MyAddin属性的时候就可以获得到MyLogger的实例。
发现部件
MEF提供三种方式发现部件
AssemblyCatalog 在当前程序集发现部件。
DirectoryCatalog 在指定的目录发现部件。
DeploymentCatalog 在指定的XAP文件中发现部件(用于silverlight)
当通过不同方式发现部件的时候,还可以使用AggregateCatalog来把这些部件聚合到一起。
var catalog = new AggregateCatalog();
//把从Program所在程序集中发现的部件添加到目录中
catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
//把从指定path发现的部件添加到目录中
catalog.Catalogs.Add(new DirectoryCatalog("C:\\Users\\v-rizhou\\SimpleCalculator\\Extensions"));
如何组合部件?
在加载完部件之后,要把它们放到一个CompositionContainer容器中。
var container = new CompositionContainer(catalog)
通过调用容器的ComposeParts()方法可以把容器中的部件组合到一起。
container.ComposeParts(this);
下面我们来看一下一个接口被多个类实例化
当一个接口被多个类实例化时,用ImportMany 声明,具体如下
[ImportMany]
public IEnumerable<IHelloWord> HelloWord { get; set; }
导入和导出的继承
如果某个类继承自部件,则该类也可能会成为部件。
导入始终由子类继承。 因此,部件的子类将始终为部件,并具有与其父类相同的导入。通过使用 Export 特性的声明的导出不会由子类继承。
但是,部件可通过使用 InheritedExport 特性继承自身。 部件的子类将继承并提供相同的导出,其中包括协定名称和协定类型。 与
Export 特性不同,InheritedExport 只能在类级别(而不是成员级别)应用。 因此,成员级别导出永远不能被继承。
下面四个类演示了导入和导出继承的原则。
NumTwo 继承自 NumOne,因此 NumTwo 将导入 IMyData。 普通导出不会被继承,因此 NumTwo 将不会导出任何内容。
NumFour 继承自NumThree。 由于 NumThree 使用了 InheritedExport,因此 NumFour
具有一个协定类型为 NumThree 的导出。 成员级别导出从不会被继承,因此不会导出 IMyData。
[Export]
public class NumOne
{
[Import]
public IMyData MyData { get; set; }
}
public class NumTwo : NumOne
{
//导入会被继承,所以NumTwo会有导入属性 IMyData
//原始的导出不能被继承,所以NumTwo不会有任何导出。所以它不会被目录发现
}
[InheritedExport]
public class NumThree
{
[Export]
Public IMyData MyData { get; set; }
//这个部件提供两个导出,一个是NumThree,一个是IMyData类型的MyData
}
public class NumFour : NumThree
{
//因为NumThree使用了InheritedExport特性,这个部件有一个导出NumThree。
//成员级别的导出永远不会被继承,所以IMydata永远不是导出
}
如何避免被发现?
在某些情况下,您可能需要防止部件作为目录的一部分被发现。
例如,部件可能是应从中继承(而不是使用)的基类。 可通过两种方式来实现此目的。 首先,可以对部件类使用abstract 关键字。
尽管抽象类能够向派生自抽象类的类提供继承的导出,但抽象类从不提供导出。如果无法使类成为抽象类,您可以使用 PartNotDiscoverable
特性来修饰它。 用此特性修饰的部件将不会包括在任何目录中。如下程序中,只有DataOne可以被发现。
[Export]
public class DataOne
{
//This part will be discovered
//as normal by the catalog.
}
[Export]
public abstract class DataTwo
{
//This part will not be discovered
//by the catalog.
}
[PartNotDiscoverable]
[Export]
public class DataThree
{
//This part will also not be discovered
//by the catalog.
}
元数据和元数据视图
自定义导出特性
可以对基本导出特性 Export 和 InheritedExport 进行扩展,以包括元数据作为特性属性。 在将类似的元数据应用于多个部件或创建元数据特性的继承树时,此方法十分有用。
MEF在MVC中的使用
在MVC的项目中,IOC组件是通过
DependencyResolver类中的 SetResolver(IDependencyResolver resolver)
方法来向MVC提供注册点的,所以我们只需要实现一个 IDependencyResolver
接口的MEF实现类,即可完成MEF在MVC中的注册工作。
另外考虑到Web应用程序的无状态性,即每次访问都是独立进行的,所以IOC组件产生的对象实例也必须唯一,否则不同用户的操作就可能串线,产生相互干扰。在这里,我们使用HttpContext.Current.Items集合来保存
组合容器CompositionContainer的实例,以使每个用户的数据保持独立,并且同一用户的同一个Http请求中使用同一对象实例。另外考虑到可能会有某种情况下需要手动获取组合容器中的实例,把组合容器缓存到了当前上下文中的Application中。
MefDependencySolver实现代码如下:
/// <summary>
/// MEF依赖关系解析类
/// </summary>
public class MefDependencySolver : IDependencyResolver
{
private readonly ComposablePartCatalog _catalog;
private const string HttpContextKey = "MefContainerKey";
public MefDependencySolver(ComposablePartCatalog catalog)
{
_catalog = catalog;
}
public CompositionContainer Container
{
get
{
if (!HttpContext.Current.Items.Contains(HttpContextKey))
{
HttpContext.Current.Items.Add(HttpContextKey, new CompositionContainer(_catalog));
}
CompositionContainer container = (CompositionContainer)HttpContext.Current.Items[HttpContextKey];
HttpContext.Current.Application["Container"] = container;
return container;
}
}
#region IDependencyResolver Members
public object GetService(Type serviceType)
{
string contractName = AttributedModelServices.GetContractName(serviceType);
return Container.GetExportedValueOrDefault<object>(contractName);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return Container.GetExportedValues<object>(serviceType.FullName);
}
#endregion
}
在Global.asax.cs的Application_Start方法中初始化MEF容器,由于Web应用程序中只需要在DLL中查找匹配,所以只使用DirectoryCatalog即可。

本文内容来源:
http://www.cnblogs.com/ulex/p/4186881.html
http://www.cnblogs.com/techborther/archive/2012/02/06/2339877.html
http://www.cnblogs.com/guomingfeng/archive/2013/05/21/mvc-ioc-mef.html
IOC之MEF学习的更多相关文章
- .NET自带IOC容器MEF之初体验
.NET自带IOC容器MEF之初体验 本文主要把MEF作为一种IOC容器进行讲解,.net中可用的IOC容器非常多,如 CastleWindsor,Unity,Autofac,ObjectBuil ...
- C#可扩展编程之MEF学习笔记(五):MEF高级进阶
好久没有写博客了,今天抽空继续写MEF系列的文章.有园友提出这种系列的文章要做个目录,看起来方便,所以就抽空做了一个,放到每篇文章的最后. 前面四篇讲了MEF的基础知识,学完了前四篇,MEF中比较常用 ...
- C#可扩展编程之MEF学习笔记(四):见证奇迹的时刻
前面三篇讲了MEF的基础和基本到导入导出方法,下面就是见证MEF真正魅力所在的时刻.如果没有看过前面的文章,请到我的博客首页查看. 前面我们都是在一个项目中写了一个类来测试的,但实际开发中,我们往往要 ...
- C#可扩展编程之MEF学习笔记(三):导出类的方法和属性
前面说完了导入和导出的几种方法,如果大家细心的话会注意到前面我们导出的都是类,那么方法和属性能不能导出呢???答案是肯定的,下面就来说下MEF是如何导出方法和属性的. 还是前面的代码,第二篇中已经提供 ...
- C#可扩展编程之MEF学习笔记(二):MEF的导出(Export)和导入(Import)
上一篇学习完了MEF的基础知识,编写了一个简单的DEMO,接下来接着上篇的内容继续学习,如果没有看过上一篇的内容, 请阅读:http://www.cnblogs.com/yunfeifei/p/392 ...
- C#可扩展编程之MEF学习笔记(一):MEF简介及简单的Demo
在文章开始之前,首先简单介绍一下什么是MEF,MEF,全称Managed Extensibility Framework(托管可扩展框架).单从名字我们不难发现:MEF是专门致力于解决扩展性问题的框架 ...
- C#可扩展编程之MEF学习
MEF系列文章: C#可扩展编程之MEF学习笔记(一):MEF简介及简单的Demo C#可扩展编程之MEF学习笔记(二):MEF的导出(Export)和导入(Import) C#可扩展编程之MEF学习 ...
- Spring入门IOC和AOP学习笔记
Spring入门IOC和AOP学习笔记 概述 Spring框架的核心有两个: Spring容器作为超级大工厂,负责管理.创建所有的Java对象,这些Java对象被称为Bean. Spring容器管理容 ...
- [转]MEF学习
MEF学习 :http://www.cnblogs.com/comsokey/p/MEF1.html C#可扩展编程之MEF学习笔记(一):MEF简介及简单的Demo C#可扩展编程之MEF学习笔记( ...
随机推荐
- [MySql]当虚拟机的IP地址自动更换后,JDBC使用原来的配置连不上MySql数据库时所报的异常。
Communications link failure The last packet sent successfully to the server was 0 milliseconds ago. ...
- realsense data
line: (43,350) (558,350) (-0.448628,-0.554531,0.995),(0,0,0) 0.713282 ------------------------------ ...
- 图像分割-Mask Scoring R-CNN
转载:https://zhuanlan.zhihu.com/p/58291808 论文链接:https://arxiv.org/abs/1903.00241 代码链接:https://github.c ...
- Node.js使用Express实现Get和Post请求
var express = require('express'); var app = express(); // 主页输出 "Hello World" app.get('/', ...
- iOS开发之—— 加密使用(MD5,base64,DES,AES)
基本的单向加密算法: BASE64 严格地说,属于编码格式,而非加密算法 MD5(Message Digest algorithm 5,信息摘要算法)SHA(Secure Hash Algorithm ...
- python-Web-flask-路由和视图
1 路由和视图: 简介: Flask框架包含两个核心:Werkzeug工具箱,Jinja2模板引擎 flask: 提供基本功能,属于轻量级 django: 提供相对完整功能,重量级 搭建虚拟环境 He ...
- 【世界之大,我用Python】Ubuntu 自动删除自带软件
起因 Ubuntu是用来做开发程序的系统,如果存在大量的"垃圾"软件就不好了吧,不仅影响系统性能而且还会经常报错,所以每次安装完系统都会清理一次系统. 操作 我清理系统一般都是直接 ...
- Unity动态批处理和静态批处理学习
本文转自:http://blog.csdn.net/lyh916/article/details/45725499,请点击链接查看楼主大神原文,尊重楼主版权. 参考链接:Unity圣典:http:// ...
- Impacket网络协议工具包介绍
转载自FreeBuf.COM Impacket是一个Python类库,用于对SMB1-3或IPv4 / IPv6 上的TCP.UDP.ICMP.IGMP,ARP,IPv4,IPv6,SMB,MSRPC ...
- redis同步到磁盘