Asp.net 面向介面可擴展框架之核心容器(含測試代碼下載)

来源:http://www.cnblogs.com/xiangji/archive/2016/04/23/5423613.html
-Advertisement-
Play Games

新框架的容器部分終於調通了!容器實在太重要了,所以有用了一個名詞叫“核心容器”。 容器為什麼那麼重要呢?這個有必要好好說道說道。 1、首先我們從框架名稱面向介面編程說起,什麼是面向介面編程?(這個度娘回答一下) 解讀一下:類是個體的定義(建模), 個體的每一方面都可以是一個介面 說白點,其一介面可以 ...


新框架的容器部分終於調通了!容器實在太重要了,所以有用了一個名詞叫“核心容器”。

容器為什麼那麼重要呢?這個有必要好好說道說道。

1、首先我們從框架名稱面向介面編程說起,什麼是面向介面編程?(這個度娘回答一下)

      解讀一下:類是個體的定義(建模), 個體的每一方面都可以是一個介面

      說白點,其一介面可以代表對象(類)一個方面,再說透點對象可能是多面手(繼承多個介面),能在不同場景(作為不同介面的實例)下正常工作

      其二每個介面可以有不同實現,只要實現了這個介面,基本上就可以替換這個位置來正常工作

2、我覺得面向介面編程本質上還是面向對象編程,只是抽象層次更高,更便於擴展和替換

     我們需要很多很多的對象來支撐系統的功能需要和擴展需求,還需要每個位置上的對象方便“隨時”替換,擴充

     那我們怎麼來管理這個龐大的對象庫呢,如何方便的編排以便管理?這裡就要說到容器了,容器可以很好的勝任這個工作。

3、容器的作用

  我認為容器就是倉庫,就是柜子,就是盒子,以便我們可以按自己喜歡的方式存放自己的對象,以便需要的時候能方便的找到他們

      好的容器還能維護對象的創建、生命周期、控制反轉(IOC)、依賴註入(DI)、攔截方法執行(AOP)等


前面廢話太多,老規矩先上例子

一、對象的創建和管理由容器負責

1、以下還是前面那篇上下文的例子,使用容器來簡化後的代碼

 以上代碼是不是簡單漂亮多了

 2、代碼雖然簡單了,功能一點都沒有水分哦,看看以下執行結果截圖

是不是結果上一篇的完全一樣啊。

3、結果一樣不算什麼,改個配置(不改代碼),看看結果

4、再改配置(還是不該代碼)

這次生動了吧,一家人各有各的個性了,是不是很炫啊。

5、大家看看配置

明眼人一眼就能看出這個是Unity容器的配置;有人說,你不是不要依賴Unity容器嗎?我發誓確實沒有依賴Unity容器,但我也沒說不用Unity啊。我只是要做一個框架,其他技術方案都可以集成進來,容器也是。

你熟悉Unity就用Unity,你熟悉Spring.net也可以放心使用,只要你封裝一下並繼承這個框架的容器介面,再註冊進來就可以正常工作了

 

二、使用了Unity容器,但不依賴Unity容器

1、調用容器的地方沒有依賴Unity

這個測試項目除了系統的幾個引用,就只引用了這個主框架了

2、主框架沒有引用Unity容器

沒騙你們吧?真沒依賴Unity,主框架甚至除了幾個簡單的系統引用,沒有依賴(引用)任何第三方組件,但是這一點都不影響我使用大量第三方的庫,因為這裡是"面向介面可擴展框架"

是不是現在又對介面有了進一步的理解了,是不是“面向介面可擴展框架”這個名字有點名符其實味道了。

 

三、下麵來解密他到底怎麼運行的

1、看入口,看應用程式(這裡是控制台程式)的引用

哈哈,是不是找到了,終於看到Unity引用了

但是不要被表象所迷惑,其實這裡的主角是Fang.Unity,因為這個項目可以不直接引用Unity容器,Fang.Unity是對Unity容器的封裝。

控制台程式對Unity相關dll是運行時依賴,並不是編譯依賴,這裡直接引用上是為了便於調試

2、繼續探究原理

Fang.Unity總不會是自動運行的吧?當然不是,上代碼

上圖有一句不起眼,但是非常重要的一行代碼“Fang.Unity.ContainerFactory.Init()”,他就是“罪魁禍首”了

換句話話說,Unity容器是完全作為插件在本框架中運行的,如果我不調用Unity的Init,調用Spring.net的Init,那當前所有地方調用的就都是Spring.net容器了。

有人說這也太不方便了吧,當然不是每次使用容器都要調用,如果是web項目可以在global的Application_Start中調用一下就Ok了,也可以在HttpModule的Init中調用也可以。

大部分時候我們在開發中大量使用容器,但並不用想我具體用什麼容器。

換句話說,我熟悉Unity容器,我使用Unity容器配置調試通過的組件給你使用,但是你一直都用Spring.net(或者其他容器),你調用Spring.net容器的封裝,把配置修改為Spring.net的配置,代碼一樣能正常運行

註:前提是組件開發的時候使用的是框架的容器支持,沒有直接引用Unity容器和直接調用Unity容器的代碼

3、還是看一眼Fang.Unity.ContainerFactory.Init是什麼鬼吧(哈哈,要不睡不著了)

Unity容器就不在這裡展開,我會單開一篇講Unity容器和Unity封裝等

 

四、核心容器解析

1、容器相關實現類截圖

2、核心類圖如下:

稍作解析各個類的分工:

     A:IContainer介面是定義容器需要的基本功能

     B:IContainerFactory定義容器工廠介面

     C:GlobalContainer是個靜態配置類,提供註冊外部容器組件功能及提供調用容器的Api

這個是實現容器插件化的關鍵,這個實現是參考了Asp.net Mvc的DependencyResolver

   D:SimpleContainer提供一個簡單和預設的容器和容器工廠實現

  AppContext中的上線文容器就是他實現的,如果不配置擴展容器功能,使用的容器就是他了,但是他其實就是一個字典緩存,存個東西,取個東西,完全沒有問題,複雜配置及DI等就沒戲了

   E:ContainerWrapper是個容器封裝攔截類,攔截容器的操作,以便增加特性和功能

       這個以後再展開講,裡面有一個很有意思的特性

   F:ContainerFactoryCacheWrapper是容器工廠封裝及緩存

       也就是外面實現的容器工廠是不用考慮單例模式緩存什麼的,他給包辦了,而且把每個生產好的容器對象檢查和打包好

 

五、多容器的應用

1、我們需要多個容器來編排眾多對象

就好比我從超市一次性買回來很多東西,有雞蛋、排骨、蔬菜、兒童玩具、衣服等等。我不能弄一個大箱子全部放進去,也不亂放,不能把衣服和排骨一起放冰箱(會被媳婦罵死的)。排骨進冰箱冷凍室,雞蛋和蔬菜進冰箱冷藏室。兒童玩具放兒童床。衣服放衣櫃。

代碼做了微調,再看運行結果

 有人說,你怎麼越改越複雜啊,代碼複雜一點點,但是配置更加有條理有的時候是值得的,看配置

這隻是一個簡單拆分容器的方案,也可以按對象圖譜來劃分容器,這樣更加合理,因為對象之間有相互的依賴關係,使用容器來做控制反轉也就是這個意思

如果是支持子容器的容器工具(Unity就支持),一個系統就可以按樹狀劃分容器,整個系統的公共配置是根容器,每個子系統都有各自的容器配置,每個子系統的各個模塊也有自己的容器配置,子容器可以繼承父容器也可以覆蓋父容器的配置

2、下麵做一個樹狀子容器的例子

這個效果是不是杠杠的,代碼也是漂亮的一塌糊塗,是怎麼配置的,也看一下吧

總結一下,容器名是優美的鏈式語法,配置文件是樹狀管理結構,Perfect!!!

 

六、容器擴展

1、SimpleContainer容器不"Simple"

前面有介紹IContainer介面,細心看一下就會發現有添加(Regist)和讀取(Resolve)方法,但是沒有刪除對象的方法,我們要刪除怎麼辦

但是SimpleContainer可是有Remove方法,使用框架的容器功能就要放棄自己更加強大的容器功能是不是有點遺憾,可不可以魚和熊掌兼得?當然可以,上下文那個就是用SimpleContainer實現的,作用域結束就從容器中刪除對象。

我們這裡再舉一個簡單的例子演示一下

使用完整的框架容器支持還是可以使用自定義容器的更多功能技巧就是IContainer介面有一個Provider屬性用來對外暴露原容器對象的Provider屬性,只要把自己想擴展暴露的擴展功能放在Provider屬性中即可

當然也可以和SimpleContainer的Provider直接返回容器本身

細心的用戶可能註意到這個例子裡面出現一個新的東西(Fang.Framework.Factory.Create),這個和前面的GlobalContainer.Factory.Create效果是一樣的,Fang.Framework.Factory是個靜態類,負責把框架的主要工廠方法都彙總起來,以便查找和使用。

但是還是要特別強調一下,這種擴展方式雖然簡單,但是並不推薦使用

因為你一旦對Provider強制類型轉化的時候你就依賴特定的容器實現了,這樣這些的代碼就可能不能適應其他容器,也就是說你的代碼強依賴特定的容器,這樣就違背了本框架的精神。

一句話,你需要更多的特性就會犧牲一些通用性,如果每段代碼都是特例,不能擴展,那這個系統就該有麻煩了。

 

2、使用ContainerWrapper的擴展

2.1 前面有提到ContainerWrapper時用來包裝容器的,通過框架產生的容器(IContainer)對象都是被ContainerWrapper包裝過的,而且ContainerWrapper攔截IContainer所有的方法

只要定義一個容器包裝類繼承ContainerWrapper,重寫自己想要擴展的功能,定義一個ContainerFactory類(繼承IContainerFactory)返回的包裝後的容器對象,框架裡面有調用一個CheckWrapper方法處理新產生的容器對象,如果對象可以轉化為ContainerWrapper對象就不需要再次包裝了

2.2 還有一個擴展技巧就是先按沒有擴展的方式註冊容器工廠

然後對容器工廠再次擴展返回ContainerWrapper對象,也就是自己定義容器封裝功能代替框架預設的封裝邏輯

以後可能會開發一個通用DI標註擴展功能,就打算使用這種方式,獲取對象的時候檢查當前對象或者類型是否有對應標註(Attribute),如果有就調用特殊邏輯處理,沒有統一的DI標註,使用DI就不得不依賴特定容器,這樣就會影響代碼復用性和可遷移性。

 

七、容器"黑科技"

1、快速檢索

用黑科技來改造樹狀結構的例子

可以配置很多容器來管理對象,但調用我們卻不用直接和每個容器打交道,只要按一定規則命名,可以使用任一個容器對象來調取任一個對象配置

如果以上黑科技再配合上DI,那就更Perfect了!!!

註:這裡面有一個插曲,一個工程師使用容器配置DI,他指著一個配置文件裡面的一個節點對我說,我想要把這個節點DI到我的Controller上。我對他解釋,"DI不能這樣的,你必須把這個節點放在根容器中,或者定義一個分區並指向一個容器,然後把這個節點複製到那個新容器中"。這個工程師聽得滿頭霧水,迷茫的說"我只是想把這個節點映射到我的Controller上,...";有了這個黑科技,我可以放心告訴他,你寫一個DI標註就可以了

 

就寫這麼多了,還有很多東西要寫,也有很多功能待開發,以後再補充吧。

提供測試源代碼下載

特別強調,本框架還在開發中,並沒有進行完全測試,不排除有重大bug的可能性,切忌暫時不要拿到自己現實項目中,出現問題後果自負,而且本框架還沒有正式開源,沒有開源授權。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 先查看一下系統版本,本例採用的操作系統是CentOS 6.5: 如果你是初裝之後的操作系統,那麼有可能wget這個組件是不存在的,所以你要安裝一下它,這樣才可以讓你從網上down下你要的安裝包: 上面這幅圖是檢查一下你是否安裝過wget組件,如果沒有的話用下麵這條語句安裝一下它即可: 當然如果你不檢 ...
  • 在請求WebApi 的時候,我們更想知道在請求數據的時候,調用了哪個介面傳了什麼參數過來,調用這個Action花了多少時間,有沒有人惡意請求。我們可以通過記錄日誌,對Action進行優化,可以通過日誌追蹤是哪個用戶或ip惡意請求。 在項目中引用log4net.dll 定義一個WebApiMonito ...
  • ahsupermarketshopping AH外貿公司英文企業網站源碼 http://www.51aspx.com/Code/AHForeignTradeCompanyrayxietongoa RayOA協同辦公服務平臺源碼 http://www.51aspx.com/code/RayXieTon ...
  • 昨天是周五太放鬆了,晚上沒有加班只顧著放鬆,玩了一晚上,今天又是睡了一上午,沒有學習。這下放鬆過分了沒有總結,也沒有完成任務。今天來總結一下昨天的學習成果。 昨天設計的資料庫今天老大點評了一下發現問題確實很多。比如用戶表和許可權表的拆分問題,是否應該拆分取決於許可權的使用頻率。使用頻率高時因該拆分。 對 ...
  • 近些天,看了一些博客園大牛關於webApi項目的的文章,也有請教師兄一些問題,自己做了個Demo試了試,收穫甚多。感謝感謝,下麵是我一些學習的總結,如若有錯的地方請多多指教!! WebApi登陸與身份驗證 因為在調用介面的時候都必須傳sessionKey參數過去,所以必須先登錄驗證身份。 如果是已註 ...
  • 今天幫同事看一個問題,她用為了實現動畫效果用主線程執行Thread.Sleep,然後界面就卡死了。 這個問題好解決,new 一個Thread就行了,但是更新WPF的界面需要主線程的操作,然後習慣性的打出Invoke,但是居然沒有。百度了一下發現WPF要用Dispatcher.Invoke ,故寫篇日 ...
  • 兩種方法,一種是利用error.StackTrace,另外一種是try-catch找到錯誤行數,具體如下: 一、error.StackTrace代碼 int i = ex.StackTrace.IndexOf("行號"); 二、try-catch代碼 try { //////////////// / ...
  • 相信博客園的讀者大多都是千萬“碼農”中的一員,每個人都寫過很多代碼,但並不是每一個人都能寫出高質量的代碼。rome is not built in one day !——完成高質量的代碼也不是一蹴而就的。為了寫出高質量的代碼,我們需要藉助一些手段,“代碼重構”基本上是最常用的手段,甚至是唯一的手段。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...