【ASP.NET】 ASP.NET MVC 3 & MEF 2.0

前面一篇介紹了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應用程序,實現:

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 的引用)

發佈了143 篇原創文章 · 獲贊 10 · 訪問量 127萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章