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

来源:互联网 发布:linux查看目录大小命令 编辑:程序博客网 时间:2024/06/05 07:31

http://www.cnblogs.com/Mainz/archive/2012/02/10/2345894.html#top

本文讲述关于用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 returnnew Book
            {
                ID = 1,
                Name = "a"
            };

            yield returnnew 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的模块化开发有兴趣可以参考 这篇文章。

本文源码下载在这里。

 

原创粉丝点击