Fork me on GitHub
MEF实现IoC

ASP.NET MVC3中用内置的MEF实现IoC

本文讲述关于用Managed Extensibility Framework (MEF) 的方法来实现IoC和Asp.net的集成。很多人不知道,这个MEF貌似是个大框架,其实已经内置在.NET Framework 4.0里面了,只需要添加引用System.ComponentModel.Composition即可。MEF在Microsoft的人看来不是一个IoC/DI的工具,而是一个提供轻量级的、可扩展的、类似插件式的系统架构的、且无需配置的(Attribute Based)框架。虽然微软的人极力否认MEF是一个IoC/DI的工具,但事实是它的确可以实现Ioc/DI。而且相对于Spring.net这样的框架来说,它的优势就是首先它是.NET Framework内置的,你无需添加第三方的引用,担心第三方组件的更新等问题;其次它是免配置的,对Spring.net这样的庞然大物来说免配置很有诱惑力。对Unity来说,它的优势是一样的,.NET Framework内置,无需配置,无需hard code的声明。当然更无需直接引用了,这是所有IoC都做到的。MEF还可以通过metadata自动发现Parts而无需获取parts的assembly/dll。有关MEF的完整的介绍,请移步MSDN:http://msdn.microsoft.com/en-us/library/dd460648.aspx。 

这里给出一个例子,用在Asp.net MVC3里面,主要场景是在Controller里通过接口获取中间层的实例,本文主要是演示MEF在Asp.net MVC3中的应用,其它丰富的应用完全可以发挥你自己的想象力。本文源码下载这里

整个项目的结构如下图:

 

在Controller中需要调用IBookService与IPhoneService: 

  

Controller的代码:

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Service.Interface;

namespace Mvc3_MEF_WebApplication.Controllers
{
    [Export]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class HomeController : Controller
    {
        private readonly IBookService _bookService;
        private readonly IPhoneService _phoneService;

        [ImportingConstructor]
        public HomeController(IBookService bookService, IPhoneService phoneService)
        {
            _bookService = bookService;
            _phoneService = phoneService;
        }

        public ActionResult Index()
        {
            ViewBag.Message = "Welcome to ASP.NET MVC!" + 
                _bookService.GetAllBooks().ToList()[0].Name + 
                _phoneService.GetAllPhones().ToList()[0].SerialNumber;

            return View();
        }

        public ActionResult About()
        {
            return View();
        }
    }
}

BookService的实现:

 

BookService的代码:

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using Data.Model;
using Service.Interface;

namespace Service.Implement
{
    [Export(typeof(IBookService))]
    public class DefaultBookService : IBookService
    {
        public IEnumerable<Book> GetAllBooks()
        {
            yield return new Book
            {
                ID = 1,
                Name = "a"
            };

            yield return new Book
            {
                ID = 2,
                Name = "b"
            };
        }
    }
}

在Global.asax.cs里面需要设置MEF dependency resolver,自动加载所有bin目录下面的assembly/dll

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);

            //Set MEF dependency resolver
            var catalog =
               new DirectoryCatalog(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin"));
            var container =
                new CompositionContainer(catalog);
            container.ComposeParts(this);

            var mefDependencySolver = new MefDependencySolver(container);
            DependencyResolver.SetResolver(mefDependencySolver);
        }

 

MefDependencySolver的代码:

 

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Web.Mvc;

namespace Mvc3_MEF_WebApplication.Extension
{
    public class MefDependencySolver : IDependencyResolver
    {
        public MefDependencySolver(CompositionContainer compositionContainer)
        {
            _compositionContainer = compositionContainer;
        }

        private readonly CompositionContainer _compositionContainer;

        public object GetService(Type serviceType)
        {
            var name = AttributedModelServices.GetContractName(serviceType);
            return _compositionContainer.GetExportedValueOrDefault<object>(name);
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            return _compositionContainer
                       .GetExportedValues<object>(serviceType.FullName);
        }
    }
}

 

 

 

最后系统运行的结果如下图:

 

 

小结

总结一下所有的步骤:

1. 项目添加引用: System.ComponentModel.Composition

2. 为需要的Parts标注[Import] [Export] 等attribute

3. 创建一个CompositionContainer实例

4. 实现IDependencyResolver接口

5. 注册到DependencyResolver

 

更多资源

本文的实现很简单,抛砖引玉,更多内容可以参考以下资料:

1. MSDN: MEF Overview 

2. MEF Programming Guide

3. MSDN Magazine: Building Composable Apps in .NET 4 with the Managed Extensibility Framework

 

另外StackOverflow还有很多针对MEF高级议题(importMany集合导入, lazy惰性导入, composition/AllowMultiple复合,  metaData, lifetime等高级议题。)的讨论,可以参考下。

 

此外,用MEF为Asp.net mvc 创建一个ControllerFactory可以参考这篇文章。 (用Unity的可以参考Artech这篇文章。)

用MEF实现Asp.net MVC的模块化开发有兴趣可以参考 这篇文章

 

 

本文源码下载这里

 

 

@:博主推荐您使用FirefoxChromeOpera浏览器浏览以获得最佳视觉效果 
@:Mainz → http://www.cnblogs.com/Mainz → 博文如非注明,均为原创敬请注意.
®: 博文是本人当时的学习笔记及知识整理,由于自身局限错误在所难免,敬请斧正. 博文中源码只作为例子学习参考之用,不保证能运行,对后果不负任何责且无任何质保,如有不明请给我留言 
©: 本文版权属于博客园和本人,版权基于署名 2.5 中国大陆许可协议发布,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接和署名Mainz(包含链接),不得删节,否则保留追究法律责任的权利。

 

ASP.NET MVC3中用内置的MEF实现IoC

posted @ 2012-02-10 17:50 Mainz 阅读(938) | 评论 (13) 编辑

私有静态方法private static method-值得用吗?
摘要: 用Resharper的同学都知道,如果你写了一个私有函数,这个函数没有访问类里面的其他参数和方法,那么它建议你标记这个方法为私有静态方法,提示是这样的: 值得这样做吗?看看微软的建议: ...阅读全文

posted @ 2011-12-14 12:06 Mainz 阅读(159) | 评论 (0) 编辑

今天代码Review发现的C#闭包问题,请做题
摘要: 今天给同事的代码做了一个CodeReview,发现了一些潜在的问题/bug,有很多是基于C#的语法糖很炫而又不理解其深层含义导致。下面就举个例子,是关于C#的闭包的,新手很容易犯,你看看下面的程序,能...阅读全文

posted @ 2011-11-02 12:04 Mainz 阅读(2007) | 评论 (33) 编辑

MEF的ImportingConstructor的异常处理
摘要: 在MEF的Import中,有属性导入和构造器导入两种方式,前者类似: 1: [Import] 2: public IMessageSender MessageSen...阅读全文

posted @ 2011-10-17 10:48 Mainz 阅读(255) | 评论 (0) 编辑

用并发队列(ConcurrentQueue)实现多线程任务中随时异步回调进度通知(.Net4.0)
摘要: 本文讲述实现抽象出来的异步通知回调进度通知,用在多层组件中,支持一组task的任意进度回调通知。本文中用到几个.NET 4.0的新方法和TPL方法:Tuple,ConcurrentQueue,Sema...阅读全文

posted @ 2011-10-13 10:56 Mainz 阅读(383) | 评论 (4) 编辑

VisualStudioVS2010统计代码行数(免安装插件)
摘要: 按CTRL+SHIFT+F (Find in files),勾上支持正则表达式,然后输入搜索内容: ^:b*[^:b#/]+.*$#开头和/开头或者空行都不计入代码量。如果需要只统计代码文件的代码量...阅读全文

posted @ 2011-09-28 12:17 Mainz 阅读(614) | 评论 (0) 编辑

[.NET]Event handler没有注销就会内存泄露吗?
摘要: 我们经常会写EventHandler += AFunction; 如果没有手动注销这个Event handler类似:EventHandler –= AFunction 会内存泄露吗?会! 这个Eve...阅读全文

posted @ 2011-09-10 14:20 Mainz 阅读(249) | 评论 (0) 编辑

C#的Dictionary值排序和SortedDictionary键排序

posted @ 2011-06-29 10:25 Mainz 阅读(1569) | 评论 (1) 编辑

WeakPropertyChangedListener用弱引用事件订阅防止内存泄露

posted @ 2011-06-25 15:25 Mainz 阅读(246) | 评论 (0) 编辑

Failed to access IIS metabase(IIS Exception Problem)

posted @ 2011-05-18 09:40 Mainz 阅读(412) | 评论 (0) 编辑

[Silverlight入门系列]Silverlight卡片翻转动画效果/x轴Y轴Z轴旋转
摘要: 使用silverlight的PlaneProjection 类很容易创建对象透视效果和类似三维效果。这个类在System.Windows.Media类库中。使用该类可以使得对象沿着x轴,y轴,z轴和任...阅读全文

posted @ 2011-04-27 11:54 Mainz 阅读(613) | 评论 (1) 编辑

动态设置和修改Membership/Profile/RoleProvider的ConnectionString数据库连接字符串

posted @ 2011-04-14 16:12 Mainz 阅读(289) | 评论 (0) 编辑

LINQ使用细节之.AsEnumerable()和.ToList()的区别

posted @ 2011-04-08 15:04 Mainz 阅读(1090) | 评论 (3) 编辑

初识LINQ中的Expression表达式树
摘要: 在上文中给C#菜鸟们介绍了《C#的delegate/event/Action/Func/Predicate关键字》和《C#4.0的dynamic和var及object关键字辨析》,今天继续说一下LIN...阅读全文

posted @ 2011-03-11 16:40 Mainz 阅读(430) | 评论 (0) 编辑

C#的delegate/event/Action/Func/Predicate关键字
摘要: 在上一篇《C#4.0的dynamic和var及object关键字辨析》中温习了.net 4.0的dynamic关键字,今天看看C#的delegate/event/Action/Func/Predica...阅读全文

posted @ 2011-03-11 12:53 Mainz 阅读(906) | 评论 (4) 编辑

C#4.0的dynamic和var及object关键字辨析
摘要: 看看代码: 1: dynamic a = 10; 2: a = a + 10; 3: Console.WriteLine(a.GetType());此段代码会输出 System.Int32,第二行不需...阅读全文

posted @ 2011-03-10 18:01 Mainz 阅读(518) | 评论 (2) 编辑

protobuf/json/xml/binary/Thrift数据交换

posted @ 2011-03-07 10:58 Mainz 阅读(1243) | 评论 (0) 编辑

生产中遇到的IIS启用GZip的深层问题

posted @ 2011-03-07 10:18 Mainz 阅读(217) | 评论 (0) 编辑

LINQ.Contains超过2100记录报异常Exception的问题

posted @ 2011-03-04 17:49 Mainz 阅读(468) | 评论 (0) 编辑

读取xml包含问号的错误:Data at the root level is invalid

posted @ 2011-01-18 16:19 Mainz 阅读(480) | 评论 (0) 编辑

搜索提示的实现(仿百度):附源码和在线demo

posted @ 2010-12-24 23:13 Mainz 阅读(905) | 评论 (10) 编辑

Aptana深色主题(编辑js,css,html)
摘要: Aptana编辑器用来编辑js,css和html还不错,这个深色主题可以下载。效果截图: css: 导入到Aptana的方法: 打开菜单window – Preferences - 搜索colors...阅读全文

posted @ 2010-12-06 16:57 Mainz 阅读(422) | 评论 (0) 编辑

使用Spring.NET统一ASP.NET异常处理并记录日志

posted @ 2010-12-06 11:53 Mainz 阅读(501) | 评论 (0) 编辑

新浪微博OAuth第三方登录C#源代码下载

posted @ 2010-12-01 17:54 Mainz 阅读(5516) | 评论 (83) 编辑

静态方法(Static)到底该不该用?

posted @ 2010-12-01 11:00 Mainz 阅读(556) | 评论 (2) 编辑

Remoting在多IP多网卡内外网环境下的问题

posted @ 2010-05-06 12:58 Mainz 阅读(468) | 评论 (2) 编辑

谈谈windows+IIS+.NET与Linux+Apache(Nginx)+Java之争

posted @ 2010-04-26 16:49 Mainz 阅读(645) | 评论 (1) 编辑

自动给URL地址加上超链接
摘要: 用户发表帖子或回复,一般网站都有一个超链接的按钮,其实可以后台自动判断并自动给URL地址加上超链接(当然,名字只能是url地址)。例如用户输入“看我的博客:http://www.cnblogs.com...阅读全文

posted @ 2009-12-14 10:56 Mainz 阅读(290) | 评论 (0) 编辑

使用Office组件读取Excel,引用Microsoft.Office.Interop.Excel出现的问题
摘要: 操作背景:asp.net操作Excel 出现问题:在本地添加引用(com):Microsoft Office 11.0 Object Library,并写好程序调试正常,部署到服务器时,出现异常 E...阅读全文

posted @ 2009-11-11 16:49 Mainz 阅读(3577) | 评论 (3) 编辑

ASP.NET服务器控件刷新后仍旧保持滚动位置
摘要: 例如常见的服务器控件Repeater+分页控件实现重复性列表很好用,但如果这些控件放置在页面尾部,点击分页的“下一页”页面PostBack后将回到顶部,而不是原来的滚动条位置,很讨厌。如果要让页面自动...阅读全文

posted @ 2009-08-21 17:47 Mainz 阅读(220) | 评论 (0) 编辑

显示ASP.NET页面装载进度
摘要: ASP.NET的web应用越做越大,即便用了AJAX也是要装载很多JS或者外部框架,导致大型应用启动装载很慢。这儿演示了一个类似Splasher的显示ASP.NET页面装载进度的方法。只要继承LoadingNotifier,调用几个JS方法即可。阅读全文

posted @ 2009-03-24 15:17 Mainz 阅读(514) | 评论 (4) 编辑

实用正则表达式匹配和替换
摘要: 正则表达式非常有用,查找、匹配、处理字符串、替换和转换字符串,输入输出等。而且各种语言都支持,例如.NET正则库,JDK正则包, Perl, JavaScript等各种脚本语言都支持正则表达式。下面整理一些常用的正则表达式 ...阅读全文

posted @ 2009-03-14 12:54 Mainz 阅读(1971) | 评论 (0) 编辑

IList(T)转换DataSet
摘要: IList转换成DataSet阅读全文

posted @ 2009-01-04 11:17 Mainz 阅读(289) | 评论 (0) 编辑

读取SQLServer数据库存储过程列表及参数信息
摘要: C#读取数据库存储过程列表: select * from dbo.sysobjects where OBJECTPROPERTY(id, N'IsProcedure') = 1 order by name...阅读全文

posted @ 2008-11-23 16:52 Mainz 阅读(2724) | 评论 (8) 编辑

Windows系统单个进程最多线程数2000个?
摘要: 在Windows下写个程序,一个进程Fork出2000个左右线程就会异常退出了,为什么? 这个问题的产生是因为windows32位系统,一个进程所能使用的最大虚拟内存为2G,而一个线程的默认线程栈StackSize为1024K(1M),这样当线程数量逼近2000时,2000*1024K=2G(大约),内存资源就相当于耗尽。 阅读全文

posted @ 2008-09-23 20:35 Mainz 阅读(1602) | 评论 (0) 编辑

无缩进的XML字符串的处理

posted @ 2008-05-02 13:20 Mainz 阅读(197) | 评论 (0) 编辑

Tail -f
摘要: 用C#写了一个Tail -f 类似的小工具,用法说明:1. 编辑runTail.bat文件,修改路径和需要跟踪的文件路径和名称 2. 运行runTail.bat 
阅读全文

posted @ 2008-04-30 12:59 Mainz 阅读(105) | 评论 (0) 编辑

Array.Sort和快速排序
摘要: 最近测试了一个自己写的快速排序,和System.Array.Sort做了个性能对比,发现System.Array.Sort比自己写的排序算法要快很多,拿20W和1000W随机数来测试效率相差40%左右。微软MSDN上对System.Array.Sort的说明:“Array 中的每个元素均必须实现 IComparable 接口,才能与 array 中的其他所有元素进行比较。 如果排序不能成功地完成,则结果未定义。此方法使用 QuickSort 算法。此实现执行不稳定排序;亦即,如果两元素相等,则其顺序可能不被保留。相反,稳定排序保留相等元素的顺序。 一般情况下,此方法的运算复杂度为 O(n log n),其中 n 是 array 的 Length;最坏的情况下其运算复杂度为 O(n ^ 2)。” 阅读全文

posted @ 2008-04-22 13:06 Mainz 阅读(1777) | 评论 (9) 编辑

反序列化的性能(Deserialization Performance)
摘要: 反序列化xml配置文件到一个实体类,和直接读取xml到实体类相比,效率对比相当大,我简单测试了一下,各自占用的时间: 反序列化需要的时间是直接读取xml的几十倍。由此可见,反序列化的性能很差,占用时间非常大。在简洁代码的背后是效率的代价。应该根据需要按需选择。尤其是在系统启动的时候尽量避免Deserialization。最后分析了使用XSD装载XML,并反序列化到实体类的例子。阅读全文

posted @ 2008-04-16 11:24 Mainz 阅读(731) | 评论 (0) 编辑

[转]关于多线程并发:每个开发人员都应了解的内容
摘要: 现在多处理器计算机正在普及,很快,非多线程程序将处于劣势,因为它们无法利用可用计算资源中很大的一部分。 不幸的是,编写正确的多线程程序并不容易。这主要是因为程序员们还没有习惯“其他线程可能正在改变不属于它们下面的内存”这种思维方式。更糟糕的是,出现错误时,程序在绝大多数时候会继续运行下去。只有在有压力(正式运行)条件下,Bug 才会显示出来;发生故障时,极少有足够的信息可供有效地调试应用程序。本文讨论多线程和共享内存线程模型,争用及并发访问如何能够打破不变量,作为争用标准解决方案的锁定,何时需要锁定,如何使用锁定;理解开销,锁定如何能够各行其道。阅读全文

posted @ 2008-04-13 21:11 Mainz 阅读(942) | 评论 (0) 编辑

记录log中的16进制和ASCII码字符输出
摘要: 写通信程序常常需要把发出和收到的包记录到log文件,而最常用的记录方式就是16进制和ASCII码左右对照的方式阅读全文

posted @ 2008-04-11 12:32 Mainz 阅读(441) | 评论 (0) 编辑

string和byte[]的转换 (C#)
摘要: C#中string类型转成byte[],byte[]转成string,string类型转成ASCII byte[],ASCII byte[] 转成string,byte[] 转成原16进制格式的string,16进制格式的string 转成byte[]阅读全文

posted @ 2008-04-09 10:40 Mainz 阅读(27365) | 评论 (7) 编辑

C#集合类(HashTable, Dictionary, ArrayList)与HashTable线程安全
摘要: HashTable中的key/value均为object类型,由包含集合元素的存储桶组成。存储桶是 HashTable中各元素的虚拟子组,与大多数集合中进行的搜索和检索相比,存储桶可令搜索和检索更为便捷。每一存储桶都与一个哈希代码关联,该哈希代码是使用哈希函数生成的并基于该元素的键。HashTable的优点就在于其索引的方式,速度非常快。如果以任意类型键值访问其中元素会快于其他集合,特别是当数据量特别大的时候,效率差别尤其大。阅读全文

posted @ 2008-04-06 13:50 Mainz 阅读(4047) | 评论 (3) 编辑

AppDomain以及如何改变web.config / App.config位置
摘要: AppDomain (应用程序域) 是.NET框架独有的概念。找不到其他技术体系中贴切的参照概念,是微软自己的东西。AppDomain,它是一个应用程序在其中执行的独立环境,为执行托管代码提供隔离、卸载和安全边界。本文还讨论了如何创建和卸载应用程序域,哪些情况下需要使用应用程序域,如何改变应用程序域的属性,以及如何改变web.config / App.config位置。阅读全文

posted @ 2008-04-03 10:47 Mainz 阅读(1347) | 评论 (1) 编辑

posted on 2012-02-12 23:15  HackerVirus  阅读(1439)  评论(2编辑  收藏  举报