如何用 MEF 扩展应用程序
最近在写一篇关于如何扩展 Visual Studio 编辑器的文章时,用到了 MEF,因此打算写一篇文章提一下这个技术点。本篇文章并不打算详细介绍 MEF,只是一个最简单的入门,相信您在阅读本篇文章后,可以迅速开发出一个可扩展的应用程序。
简 介
MEF(Managed Extensibility Framework),是微软推出的一款用于搭建可扩展应用程序的框架,起初是独立于 .Net 发布的,后来集成到了 .Net 4.0 中。使用该框架可以非常轻松地扩展一个已发布的应用程序的功能,连 Visual Studio IDE 中的代码编辑器窗口也采用了MEF的思想,因此大大方便了开发人员对编辑器的扩展。
MEF 可用在任何使用 .NET Framework 的地方。可以在客户端应用程序中使用 MEF(无论应用程序使用的是 Windows 窗体、WPF,还是任何其他技术),也可以在使用 ASP.NET 的服务器应用程序中使用 MEF。
MEF的关键概念
Import
导入,这里建议作为一个名词来理解,即一个接受者,它可以接受外来的东东。就好比是下图中的盒子,它可以接受其它积木。
十三孔智力盒
Export
导出,同样建议以一个名词来理解,即一个第三方的产物。它就像上图中不同颜色的积木,这些积木不属于这个盒子,但是能被放入盒子中,来丰富盒子的功能。
积木
Contract
协议。要想使盒子能接受积木(比如,圆柱体只能放入圆形的接口中),那这些积木必须符合一定的形状。而这些形状就相当于是应用程序和第三方扩展之间的一个协议。
Compose
组合(动词),即将多个符合协议要求的部件组合在一起,构成一个功能丰富的应用程序。就好比是将不同形状的积木,按照接口的形状组合在一起。
它是如何工作的?
MEF 会动态查找用户所指定的目录,如果发现该目录中的程序集满足协议要求,就会启动自身的组合引擎,然后根据不同的协议约定把这些扩展导入到应用程序内部。
用 MEF 实现一个最简单的可扩展应用程序
对几个关键的概念清楚了之后,我们就可以开始实践了。最终的效果是窗体上会动态加载某一目录下的dll,并自动为每个新功能添加一个按钮,当点击按钮就会执行新的功能。
最终效果
首先,定义一个协议。
这个和普通定义接口没什么两样。
public interface IPlugin
{
string Text { get; } void Do();
}
安装接受者
有了协议之后,就需要给应用程序安一个接受者。让这个应用程序可以通过接受者来获取第三方扩展。MEF 提供了[Import] 和 [ImportMany] 两种 attribute。 区别就是 Import 只能接受符合协议的一个扩展,而 ImportMany 可以接受多个,并把多个扩展放入集合中。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
} [ImportMany]
public IEnumerable<IPlugin> plugins; private void Form1_Load(object sender, EventArgs e)
{
} }
提供一个符合协议的产物
这个产物的生产过程其实就是实现接口的过程,唯一的区别是我们要为这个实现打上个标签,从而告诉我们的组合引擎这个东西是给接受者的。MEF 提供了 Export 来暗示这是一个可以提供给接受者的产物。
[Export(typeof(IPlugin))]
public class MyPlugin:IPlugin
{
public string Text
{
get
{
return "This is a demo";
}
} public void Do()
{
MessageBox.Show(Text);
}
}
发动引擎
万事俱备,就差发动了。前面说了引擎的主要作用就是把发现扩展,同时把这些扩展组合到应用程序中。
private CompositionContainer _container;
private void Init()
{
try
{
MyPlugin my = new MyPlugin();
this._container.ComposeParts(this, my);//把扩展和实例组合在一起
}
catch (CompositionException compositionException)
{
Console.WriteLine(compositionException.ToString());
}
}
上面的代码虽然实现了组合的功能,但是却硬把产物给编码进去了。要是每次开发了新的扩展,都得这样修改应用程序代码,那就完全没有使用MEF的必要了,而且也违反了开放封闭的设计原则。
把上面的代码改一改。
private CompositionContainer _container;
private void Init()
{
//设置目录,让引擎能自动去发现新的扩展
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new DirectoryCatalog("D:\\plugin\\")); //创建一个容器,相当于是生产车间
_container = new CompositionContainer(catalog); //调用车间的ComposeParts把各个部件组合到一起
try
{
this._container.ComposeParts(this);//这里只需要传入当前应用程序实例就可以了,其它部分会自动发现并组装
}
catch (CompositionException compositionException)
{
Console.WriteLine(compositionException.ToString());
}
}
上面的代码会自动去发现扩展,然后加入到应用程序中来。你要做的只是把新扩展的程序集放入 D:\\plugin 目录中就可以了。是不是很方便呢?
参考资源
Managed Extensibility Framework (MEF)
本文来源于 《如何用 MEF 扩展应用程序》
如何用 MEF 扩展应用程序的更多相关文章
- 使用Managed Extensibility Framework方便的扩展应用程序
概述 Managed Extensibility Framework(MEF)是.NET平台下的一个扩展性管理框架,它是一系列特性的集合,包括依赖注入(DI)以及Duck Typing等.MEF为开发 ...
- 【开源】前端练手笔记,Chrome扩展应用程序(html+CSS+JS) (1)
项目名称:github-notification 项目地址:https://github.com/WQTeam/github-notification 说明:本人打算抽时间学习前端(html + cs ...
- 第3章 如何用DAP仿真器下载程序
第3章 如何用DAP仿真器下载程序 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/f ...
- 第3章 如何用DAP仿真器下载程序—零死角玩转STM32-F429系列
第3章 如何用DAP仿真器下载程序 集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/firege ...
- 在小程序中实现全局混入,以混入的形式扩展小程序的api
GitHub: https://github.com/WozHuang/mp-extend 相关文章: 小程序全局状态管理,在页面中获取globalData和使用globalSetData 通过页面预 ...
- Windows Azure 安全最佳实践 - 第 6 部分:Azure 服务如何扩展应用程序安全性
多种Windows Azure服务可以帮助您将应用程序安全性扩展到云. 有三种服务可提供多个提供程序之间的身份标识映射.内部部署数据中心间的连接和相互发送消息的应用程序功能(无论应用程序位于何处). ...
- 【Python】 如何用pyinstaller打包python程序成exe
[pyinstaller] pyinstaller在他们的官方网站上下载:http://www.pyinstaller.org/ 下载完pyinstaller之后还要安装一个支持包pywin32. 这 ...
- VSCode的Python扩展下程序运行的几种方式与环境变量管理
在VSCode中编写Python程序时,由于有些地方要使用环境变量,但是发现设置的环境变量有时不起作用,花了点时间研究了一下,过程不表,直接说结论. 首先,环境变量的设置,Python扩展中有三种方式 ...
- 如何用chrome扩展将网页变成黑底白字,用以保护视力
不知道有没有科学依据,自己感觉黑底白字对视力好些,于是动手加个chrome扩展: 第一步:建个文件夹,名称比如叫changeColor; 第二步:在changeColor文件夹中建三个文件:manif ...
随机推荐
- 游戏服务器菜鸟之C#初探一游戏服务
本人80后程序猿一枚,原来搞过C++/Java/C#,因为工作原因最后选择一直从事C#开发,因为读书时候对游戏一直比较感兴趣,机缘巧合公司做一个手游的项目,我就开始游戏服务器的折腾之旅. 游戏的构架是 ...
- 几个比较”有意思“的JS脚本
1.获取内网和公网真实IP地址(引用地址) <!DOCTYPE html> <html> <head> <meta http-equiv="Cont ...
- Dapper扩展之~~~Dapper.Contrib
平台之大势何人能挡? 带着你的Net飞奔吧!http://www.cnblogs.com/dunitian/p/4822808.html#skill 上一篇文章:Dapper逆天入门~强类型,动态类型 ...
- 简析服务端通过GT导入SHP至PG的方法
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 项目中需要在浏览器端直接上传SHP后服务端进行数据的自动入PG ...
- 4.Android 打包时出现的Android Export aborted because fatal error were founds [closed]
Android 程序开发完成后,如果要发布到互联网上供别人使用,就需要将自己的程序打包成Android 安装包文件(Android Package,APK),其扩展名为.apk.使用run as 也能 ...
- 三星Note 7停产,原来是吃了流程的亏
三星Note 7发售两个月即成为全球噩梦,从首炸到传言停产仅仅47天.所谓"屋漏偏逢连天雨",相比华为.小米等品牌对其全球市场的挤压.侵蚀,Galaxy Note 7爆炸事件这场连 ...
- 解决:SharePoint当中的STP网站列表模板没有办法导出到其它语言环境中使用
首在在你的英文版本上,导出列表或是网站的模板,这个文件可能是这样滴:template.stp 把这个文件 template.stp 命名为 template.cab 解压 这个 *.cab 文件 在解 ...
- 喜马拉雅音频下载器 V1.2 支持专辑批量下载 喜马拉雅mp3下载导出 喜马拉雅下载器
出差一个星期回来看邮箱,发现好多网友评论说网站又更新了,老程序不能用了,有热心网友放出修改版的,我就不重复造车了..大家可以去这里下载 http://blog.csdn.net/suqingheang ...
- 技术笔记:Indy控件发送邮件
工作中有个需求需要发送邮件,因为使用的delphi6,所以自然就选择了indy组件,想想这事挺简单的.实现的过程倒是简单,看着Indy的demo很快就完了,毕竟也不是很复杂的功能. 功能要求: 1.压 ...
- Jexus服务器SSL二级证书安装指南
申请获得服务器证书有三张,一张服务器证书,二张中级CA证书.在Android微信中访问Https,如果服务器只有一张CA证书,就无法访问. 获取服务器证书中级CA证书: 为保障服务器证书在客户端的兼容 ...