[转载]ASP.NET MVC3中用内置的MEF实现IoC – Mainz – 博客园.
本文讲述关于用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.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.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
{
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);
}
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
更多资源
本文的实现很简单,抛砖引玉,更多内容可以参考以下资料:
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的模块化开发有兴趣可以参考 这篇文章。