前面一篇介紹了ASP.NET MVC3 和 Unity 結合使用的示例,Unity 通過 Register 方法或者配置注入實例,MEF 則是通過 [Import] [Export] 特性綁定依賴。在 MEF 2.0 中當前 dll 中如果在 *.Parts.* 命名空間下的類型會自動作爲依賴源。CompositionProvider.AddPartsAssembly 亦可運行時添加依賴對象,非常靈活。通過元數據定義的依賴和通過XML來描述依賴關係是各有利弊,XML方式勢必帶來配置和維護的學習成本(編碼注入是一種寫法,配置又是另一種寫法),而元數據定義方式使得關係凌亂分散,侵入性也較強。
最新的MEF 2.0 Preview 5 加入了 System.ComponentModel.Composition.Web.Mvc.CodePlex.dll 簡化了構建一個靈活的,可測試的ASP.NET MVC應用程序,實現:
雖然用 CompositionBatch.AddExportedValue 可以在 Global.asax 裏實例化 DbContext 注入,但是拿不到 CompositionContainer 實例,沒法完成最後的註冊...
看來有必要再研究下 CompositionProvider 的實現機制。
2. Controller 中的 IRepository Import
3. Global.asax 裏完成 AddPartsAssembly
最新的MEF 2.0 Preview 5 加入了 System.ComponentModel.Composition.Web.Mvc.CodePlex.dll 簡化了構建一個靈活的,可測試的ASP.NET MVC應用程序,實現:
1)爲Controller提供依賴注入
2)通過定義簡單的約定(Import & Export) 識別和配置 MEF Parts(組合)
3)將依賴實例的生存週期映射到Request的生存週期上
4) 簡化 ActionFilter 和 ModelBinder 的依賴注入實現
* 目前還沒有提供 nuget 的方式,所以只能下載 dll 手動添加:
1) System.ComponentModel.Composition.CodePlex.dll
2) System.ComponentModel.Composition.Web.Mvc.CodePlex.dll
下面來看看示例代碼,如何利用MEF實現ASP.NET MVC的IoC
MvcWithMefTest 是 MVC Application,Controller IoC 是目標。GenericRepository 是接口,MvcWithMefTest.Repository 是要注入的依賴。
(GenericRepository 和 Models 的代碼,參看我上篇blog:【ASP.NET】ASP.NET MVC 3 & Unity.MVC3 )
1. MvcWithMefTest.Repository 的 Export
using System;
using System.Collections.Generic;
using GenericRepository;
using MvcWithMefTest.Models;
using System.ComponentModel.Composition;
using System.Data.Entity;
namespace MvcWithMefTest.Repository
{
[Export(typeof(IRepository<User>))]
public class UserRepository : DbContextRepository<User>
{
[ImportingConstructor]
public UserRepository([Import("Database")]DbContext context)
: base(context)
{ }
}
public class InjectDbInstance
{
[Export("Database")]
public DbContext Database
{
get
{
return new DbEntities();
}
}
}
}
上面的代碼可以看到,DbContext 實例通過名稱化的 ImportingConstructor 注入。對於構造方法的實例注入,不知道還有沒有更好的辦法?雖然用 CompositionBatch.AddExportedValue 可以在 Global.asax 裏實例化 DbContext 注入,但是拿不到 CompositionContainer 實例,沒法完成最後的註冊...
看來有必要再研究下 CompositionProvider 的實現機制。
2. Controller 中的 IRepository Import
public class HomeController : Controller
{
[Import]
GenericRepository.IRepository<User> _userRepository;
public ActionResult Index()
{
var users = _userRepository.GetAll();
return View(users);
}
}
3. Global.asax 裏完成 AddPartsAssembly
protected void Application_Start()
{
Database.SetInitializer(new MvcWithMefTest.Models.SampleData());
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
CompositionProvider.AddPartsAssembly(typeof(UserRepository).Assembly);
}
這裏 AddPartsAssembly 是通過 typeof(xxx).Assembly 來實現的,完全可以通過 Assembly.LoadFrom / LoadFile 完成實際的物理分離(即 Application 工程不添加 Repository.dll 的引用)