MVC實用架構設計(二)——使用MEF實用IOC(依賴倒置)

來源:互聯網
上載者:User
〇、目錄

一、前言

二、MEF的優勢

三、MEF在傳統型程式中的使用

四、在MVC中使用MEF

五、源碼擷取

六、系列導航

一、前言

  在《上篇》中,基本的項目結構已經搭建起來了,但是有個問題,層與層之間雖然使用了介面進行隔離,但執行個體化介面的時候,還引入了介面實作類別的依賴。如:

  面向介面編程,Controller應該只依賴於網站業務層的介面,而不能依賴於具體的實現,否則,就違背了在層之間設定介面的初衷了。

  另外,如果上層只依賴於下層的介面,在做單元測試的時候,就可以用Moq,Fakes等Mock工具來按實際需求來類比介面的實現,就可以靈活的控制介面的傳回值來對各種情況進行測試,如果依賴於具體的實現,項目的可測試性將大大減小,不利於進行自動化的單元測試。

  要不依賴於具體的實現,就不能使用通常的 T t = new T() 的方式來獲得一個類的執行個體了,需要通過IOC容器來對對象生命週期,依賴關係等進行統一的管理。

二、MEF的優勢

  .net中可用的IOC容器非常多,如 CastleWindsor,Unity,Autofac,ObjectBuilder,StructureMap,Spring.Net等,這些第三方工具各不相同,但功能大體都相同,大都需要事先對介面與實現進行配對(通過代碼或設定檔),然後由系統自動或手動來通過介面來獲得相應實作類別的執行個體,對象執行個體化的工作由IOC容器自動完成。

  MEF相對於上面的這些IOC容器有什麼優勢呢?下面是我推薦的理由:

  1. .net4.0 內建:MEF的功能在 System.ComponentModel.Composition.dll 程式集中,直接引用即可使用,不用安裝第三方組件
  2. 0 配置:MEF是不需要使用設定檔或代碼對介面與實現進行一一配對的,只需要簡單的使用幾個Attribute特性,就能自動完成源與目標的配對工作
  3. 自動化:系統初始化時自動遍曆程式目錄或指定檔案夾下的dll,根據程式集中介面與類的特定Attribute特性進行自動配對。
三、MEF在傳統型程式中的使用

  在傳統型程式中,需要完成兩個部分的目錄匹配,一個是dll中的匹配,另一個為exe程式集中的匹配,分別使用到DirectoryCatalog與AssemblyCatalog兩個目錄類。而兩個目錄類需加入到 AggregateCatalog 目錄類中,才能參與組合容器CompositionContainer的初始化。

  在服務提供者的實作類別中,使用 ExportAttribute 標記要與之匹配的介面,如所示。在服務調用方,使用 ImportAttribute 來給介面注入實作類別的執行個體,如所示。

  由於調用方法為靜態方法,Program類的執行個體仍需手動從組件容器中獲得,然後嘗試登入:

  輸出結果,介面AccountContract並沒有賦值,但能輸出其實作類別的資訊,同時登入也能成功調用:

四、MEF在MVC中的使用

  在MVC的項目中,IOC組件是通過 DependencyResolver類中的 SetResolver(IDependencyResolver resolver) 方法來向MVC提供註冊點的,所以我們只需要實現一個 IDependencyResolver 介面的MEF實作類別,即可完成MEF在MVC中的註冊工作。

  另外考慮到Web應用程式的無狀態性,即每次訪問都是獨立進行的,所以IOC組件產生的對象執行個體也必須唯一,否則不同使用者的操作就可能串線,產生相互幹擾。在這裡,我們使用HttpContext.Current.Items集合來儲存 組合容器CompositionContainer的執行個體,以使每個使用者的資料保持獨立,並且同一使用者的同一個Http請求中使用同一對象執行個體。另外考慮到可能會有某種情況下需要手動擷取組合容器中的執行個體,把組合容器緩衝到了當前上下文中的Application中。

  MefDependencySolver實現代碼如下: 

 1     /// <summary> 2     /// MEF依賴關係解析類 3     /// </summary> 4     public class MefDependencySolver : IDependencyResolver 5     { 6         private readonly ComposablePartCatalog _catalog; 7         private const string HttpContextKey = "MefContainerKey"; 8  9         public MefDependencySolver(ComposablePartCatalog catalog)10         {11             _catalog = catalog;12         }13 14         public CompositionContainer Container15         {16             get17             {18                 if (!HttpContext.Current.Items.Contains(HttpContextKey))19                 {20                     HttpContext.Current.Items.Add(HttpContextKey, new CompositionContainer(_catalog));21                 }22                 CompositionContainer container = (CompositionContainer)HttpContext.Current.Items[HttpContextKey];23                 HttpContext.Current.Application["Container"] = container;24                 return container;25             }26         }27 28         #region IDependencyResolver Members29 30         public object GetService(Type serviceType)31         {32             string contractName = AttributedModelServices.GetContractName(serviceType);33             return Container.GetExportedValueOrDefault<object>(contractName);34         }35 36         public IEnumerable<object> GetServices(Type serviceType)37         {38             return Container.GetExportedValues<object>(serviceType.FullName);39         }40 41         #endregion42     }

   在Global.asax.cs的Application_Start方法中初始化MEF容器,由於Web應用程式中只需要在DLL中尋找匹配,所以只使用DirectoryCatalog即可。

   在AccountController類中加入MEF的Attribute標籤,並刪除原來建構函式中的AccountContract屬性的賦值代碼

  在加入了IOC組件之後,我們的架構就變成了面向介面編程的架構了,上層代碼僅依賴於下層的介面,而不依賴於下層的具體實現,為了防止網站業務層的實現代碼中出現如下所示的代碼:

IAccountSiteContract accountContract = new AccountSiteService();

上一篇文章中也提到過,需要把網站業務層中的實作類別的可訪問性由 public 修改為 Internal,以實現上層代碼對下層代碼的真正隔離。

  其他代碼不變,運行網站,同樣能正常調用登入功能

五、源碼擷取

   GMFrameworkForBlog2.zip

  為了讓大家能第一時間擷取到本架構的最新代碼,也為了方便我對代碼的管理,本系列的源碼已加入微軟的開源專案網站 http://www.codeplex.com,地址為:

  https://gmframework.codeplex.com/

  可以通過下列途徑擷取到最新代碼:

  • 如果你是本項目的參與者,可以通過VS內建的團隊TFS直接連接到 https://tfs.codeplex.com:443/tfs/TFS17 擷取最新代碼
  • 如果你安裝有SVN用戶端(親測TortoiseSVN 1.6.7可用),可以串連到 https://gmframework.svn.codeplex.com/svn 擷取最新代碼
  • 如果以上條件都不滿足,你可以進入頁面 https://gmframework.codeplex.com/SourceControl/latest 查看最新代碼,也可以點擊頁面上的 Download 連結進行壓縮包的下載,你還可以點擊頁面上的 History 連結擷取到曆史版本的原始碼
  • 如果你想和大家一起學習MVC,學習EF,歡迎加入Q群:5008599(群發言僅限技術討論,拒絕閑聊,拒絕醬油,拒絕廣告)
  • 如果你想與我共同來完成這個開源項目,可以隨時聯絡我。
系列導航
  1. MVC實用架構設計(〇)——總體設計
  2. MVC實用架構設計(一)——項目結構搭建
  3. MVC實用架構設計(二)——使用MEF實用IOC
  4. MVC實用架構設計(三)——EF-Code First(1):Repository,UnitOfWork,DbContext
  5. MVC實用架構設計(三)——EF-Code First(2):實體映射、資料移轉,重構
  6. MVC實用架構設計(三)——EF-Code First(3):使用T4模板產生相似代碼
  7. MVC實用架構設計(三)——EF-Code First(4):資料查詢
  8. MVC實用架構設計(三)——EF-Code First(5):二級緩衝
  9. MVC實體架構設計(四)——日誌記錄
  10. 未完待續。。。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.