標題“Mvc擴展框架及DI”有點繞口,我也想不出好的命名,因為這個內容很雜,涉及多個模塊,但在日常開發又密不可分
首先說Mvc擴展框架,該Mvc擴展就是把以前的那個Mvc分區擴展框架遷移過來,並優化整合了一下
一、Mvc擴展框架主要功能:
1、Mvc的依賴注入(DI)功能(類MvcDependency)
依賴IContainerFactory接口,不再依賴具體容器
2、Mvc全局過濾器(GlobalFilterProvider)
配置在Mvc的依賴注入容器中就能自動被Mvc調用。其實邏輯很簡單,就是繼承IFilterProvider接口,對外暴露Filters屬性,需要增加過濾器就配置到Filters屬性中
3、分模塊(Area分區)開發支持
Area基類及相關支持類(AreaRoute、AreaListService)
4、分區過濾器(AreaGlobalFilterProvider)
5、分區注冊的HttpModule(AreaMergeModule)
使用該HttpModule初始化分區及分區的依賴注入容器配置
二、依賴注入(DI)也挺復雜的
1、Mvc的依賴注入(DI)支持
Mvc使用IDependencyResolver接口定義依賴注入,實現該接口並覆蓋Mvc默認的DI配置,主要是把Mvc的依賴注入適配到容器來支持,以便使用容器來做
2、容器的依賴注入(DI)
成熟容器支持依賴注入功能,為用戶構造對象,並按當前對象(類)的依賴注入配置遞歸進行依賴注入操作
3、框架的依賴注入(DI)擴展(Fang.DI)
其一、本框架不依賴任一成熟容器,所以為了便於更好的使用DI技術,所以擴展了DI支持,以便使用任意容器功能都可以使用DI
其二、每種成熟容器的DI配置(標注)的方式不一致,導致使用特定容器的DI寫的代碼給使用其他容器技術的團隊復用性不好
其三、本框架支持“快速檢索黑科技”(參考核心容器那篇),使用該依賴注入(DI)擴展可以使用“快速檢索黑科技“語法定義依賴注入標記
本篇內容涉及”Mvc擴展框架“子模塊,”依賴注入(DI)擴展“子模塊、主框架的核心容器及外部成熟容器(本篇繼續使用Unity容器做外部成熟容器示例)
介紹的差不多了,先上例子
一、Mvc的依賴注入(DI)
1、使用Unity容器做DI
1.1 配置初始化
首先注入Unity容器,初始化Mvc依賴配置(替代Mvc默認的DependencyResolver)
1.2 建一個測試頁面,使用Unity配置一個依賴注入服務
Ok,依賴注入成功
1.3 看一下Unity容器配置
2、使用Fluent代碼做依賴注入
木有問題,效果出來。使用容器技術不一定非要用配置文件,Fluent方式也是配置容器的選項之一。當然配置文件搭配Fluent也是木有問題。
以上例子雖然簡單,但用到了很多技術,有Mvc擴展框架、Unity容器及依賴注入(DI)擴展。
二、全局過濾器
1、過濾器代碼很簡單
以上只是ActionFilter的例子,Mvc支持的AuthorizationFilter\ExceptionFilter\ActionFilter\ResultFilter都可以這樣配置,是不是很爽啊
2、看一下容器配置信息
有人說,你能用Fluent代碼再作一次過濾器的例子嗎?當然可以,只要創建一個IFilterProvider對象,注入到容器里面就可以了。沒必要再做這個重復的工作。
我是非常推薦使用配置文件的方式,項目和調用的服務具體實現類才能徹底的隔離,才能更好的體現IOC容器的作用
三、分模塊(area分區)
1、分區路由配置
2、兩個分區配置
3、執行效果
以上兩個分區運行結果,且兩個分區調用的服務稍有不同,導致結果稍不同
分區的講解不展開了,參看原來的文章”分區擴展框架“,只是分區過濾器稍有不同,后面再講解分區過濾器
四、分區過濾器
1、還是使用全局過濾的代碼,直接看結果
以上其實是分區過濾器和全局過濾器整合測試,兩個分區共用一個全局過濾器GlobalTest,每個分區還有自己的分區過濾,效果不錯吧
2、看一下過濾器配置(配置和全局過濾器是不同的)
看以上配置,分區過濾器和全局過濾器配置幾乎一致(實際上也是繼承關系),而且從分區中拆分出來,效果和原來(參看原來文章”分區擴展框架“)一樣,結構是不清晰多了,而且也減輕了area初始化的負擔,算是優化吧。
3、AreaMergeModule(分區注冊的HttpModule)配置
配置方法還是那么簡單,這方面的內容還是參看前篇文章
五、框架的依賴注入(DI)擴展(Fang.DI)
1、配置方式
和Unity的屬性依賴注入相似度很高吧,只是命名空間不一樣,但是作用大很多,還可以對不支持DI的容器進行DI(依賴注入)
2、執行效果
效果和Unity容器配置的一樣。使用DI擴展對不同容器就可以統一依賴注入語法了。但是美中不足的是,我只在依賴注入擴展模塊(Fang.DI)中實現了屬性依賴注入。
這種擴展DI並不會覆蓋原容器(比如Unity)的DI,只是補充,也會檢測DI的屬性是否已經初始化(!=null),也就是說擴展的DI是補充,原容器DI成功就不再DI,也可以同時使用(如果你不嫌亂的話)
我個人認為有屬性依賴注入就夠用了。當然很多人都有反駁的理由,最為關鍵的應該是安全性。如果我們把服務的初始化都交給容器,不要去修改服務對象,也就沒有安全一說;如果你非要修改,就算是private的,類內部也可以修改,外部使用反射也能修改,沒有絕對的安全性。
3、使用“快速檢索黑科技“語法定義依賴注入標記
上面標注中重點要看到有個點(.),本例就是把全局服務容器中的默認時間格式化服務DI到當前Controller的屬性上;也就是說可以把任意容器中的任意服務都DI過來,絕對的黑科技!!!
六、各功能模塊都是如何協同工作的
1、Mvc擴展框架、Unity容器及依賴注入(DI)擴展模塊相互獨立,相互沒有依賴關系
上圖可以清晰看到,他們相互獨立,但是他們都依賴着面向接口主框架(Fang.Framework),那主框架就非常重要,各自和主框架的關系就非常重要
(這就是我設計這個框架的初衷,以后增加再多的功能,或者引入再多的第三方組件,都只依賴主框架,都是對作為主框架的服務(插件)或者Mvc等Ms框架的插件來調用運行)
2、以上例子中各模塊式如何工作
先看項目配置
以上先注冊Unity容器,再注冊依賴注入擴展(Fang.DI),分區及其路由規則使用HttpModule注入
我們還看到一個有意思的東西,初始化DI居然和初始化Unity容器那么的相似,其實DI擴展就是容器封裝,說白了就是容器擴展,也就是說我是通過擴展容器來實現DI的
3、那我們看看依賴注入擴展(Fang.DI)怎么工作的
3.1 依賴注入擴展(Fang.DI)項目截圖
A:DependencyAttribute就是依賴注入標注(Attribute),靠他標注哪個屬性需要注入
B:Container和ContainerFactory是容器封裝,封裝后的容器對象就有了擴展出來的DI功能,所以我們調用的原始容器即使沒有依賴注入功能經過這么一封裝就有依賴注入功能了
C:PropertyChecker類就是負責找到那些屬性需要依賴注入,PropertyChecker實例對象封裝了一個屬性的依賴注入過程(功能)
D:CheckContainer定義了一個使用容器處理依賴注入的接口(ICheckContainer)及多個Checkers屬性包含多個ICheckContainer對象,並自己實現ICheckContainer接口
(其實就是容器處理依賴注入的組合模式,其中前面的PropertyChecker就是實現的ICheckContainer接口,一般來說CheckContainer對象包含一個PropertyChecker的數組)
注:這塊剛開發完,CheckContainer這個命名有點問題,以后再改,如果有建議好的命名可以回復我一下,謝謝
3.2 再來看一下CheckContainer的主要邏輯(還是比較簡單的)
解讀一下:
A:字典(ConcurrentDictionary)按類型緩存對象
B:MonitorWrapper是我寫的一個對象鎖的封裝,避免死鎖和控制鎖定的最長時間(默認50毫秒)及返回是否鎖定成功;
(既然是緩存,那鎖只是幫我們提高緩存利用率的工具,所以不管是否鎖定成功,都繼續執行)
C:如果沒有緩存,我們按類型獲取可寫並標注(DependencyAttribute)的屬性,按屬性構造注入功能(ICheckContainer)對象
D:這里的注入比較簡單,我直接使用的反射了;
(打算以后使用Emit,但是我的Emit功底太差,Emit個功能要半天,以后在好好學習Emit技巧或者花時間好好調試,為了性能不能有半點馬虎)
本篇內容就講完了。本篇內容和原來的那篇”分區擴展框架“有很多相同的地方,但本質的東西區別很大。原來的分區框架是強依賴Unity容器的,本框架是使用配置到主框架的容器工廠。
很多配置也都有更多的自定義化,而且本框架也照顧到不使用分區的開發使用者的利益(全局過濾和MvcDependency(DI))。
還有就是依賴注入擴展模塊(Fang.DI)和Mvc擴展框架無縫結合,真是如虎添翼。當然,Fang.DI在非Mvc中的也是一樣有效,這里就不舉例說明了。