Asp.net 面向接口框架之应用程序上下文作用域组件
在團(tuán)隊(duì)中推廣面向接口開發(fā)兩年左右,成果總體來說我還是挺滿意的,使用面向接口開發(fā)的模塊使用Unity容器配置的功能非常穩(wěn)定,便于共享遷移(另一個(gè)項(xiàng)目使用只需要復(fù)制配置和調(diào)用接口即可)也很好擴(kuò)展(操作的數(shù)據(jù)庫(kù)、表、資源等都可以配置)。
但是由于當(dāng)時(shí)開發(fā)的匆忙(邊開發(fā)邊應(yīng)用),留下一些比較致命的問題:
1、很多接口定義的不合理,通用性和擴(kuò)展性不好
2、固定死了使用Unity容器,如果更大面積推廣有問題,有些人已經(jīng)很熟悉其他容器了,再來重新學(xué)Unity沒有必要
3、配置比較麻煩,需要簡(jiǎn)化
所以我覺得有必要重新開發(fā)一個(gè)框架,對(duì)原框架取其精華去其糟粕,再吸收開源項(xiàng)目(含微軟開放源代碼的部分),爭(zhēng)取做出一個(gè)像樣一點(diǎn)的東西并開源出去...
這里插一句,前面有寫一個(gè)Asp.net Mvc分區(qū)擴(kuò)展框架系列沒有寫完的原因,其一是趕時(shí)間做這個(gè)框架,其二是重新做新框架,所有剩下的文章按新的框架來寫會(huì)更好
?這里要講的是本框架中一個(gè)小的組件,應(yīng)用程序上下文組件(AppContext),本組件有參考博客園大神的文章,這里先不注明出處(如果文章的作者介意,我再修改博文標(biāo)注)
下面開始介紹本組件的主要使用場(chǎng)景
1、不同對(duì)象和方法間傳遞數(shù)據(jù)的新方式,看例子
看運(yùn)行結(jié)果:
有人會(huì)說,你就作吧,修改一下A方法返回那個(gè)隨機(jī)數(shù),修改B方法增加一個(gè)參數(shù)接受這個(gè)隨機(jī)數(shù),So Easy。
但是在現(xiàn)有完成架構(gòu)上增加一個(gè)附屬功能,就把簽名改了是很恐怖的事情。實(shí)際項(xiàng)目中產(chǎn)生對(duì)象方法和其他需要調(diào)用對(duì)象的方法可能沒有調(diào)用鏈,或者調(diào)用鏈非常復(fù)雜,你要把涉及的所有方法都改一邊,那系統(tǒng)估計(jì)差不多要被你改"廢"了
在現(xiàn)實(shí)項(xiàng)目中并不推薦大規(guī)模的這樣使用,只有在擴(kuò)展附屬功能,Aop或者在現(xiàn)項(xiàng)目擴(kuò)展需要,慎重之下一個(gè)解決方案而已,性能肯定是比直接傳要差不少,權(quán)當(dāng)是應(yīng)用程序上線文緩存來使用。
以上代碼按照預(yù)期的效果運(yùn)行了,看似簡(jiǎn)單功能,后面原理還是挺復(fù)雜的
2、線程安全調(diào)用
以上用兩個(gè)線程對(duì)上下文中讀取和寫入數(shù)據(jù),看數(shù)據(jù)是否會(huì)串(線程是否安全),看執(zhí)行結(jié)果:
稍微解讀一下:
? ? ? A:線程6先運(yùn)行,從上下文中讀取鍵為test類型string的值為空,阻塞1000毫秒,再寫入鍵為test,類型為string的值1000,再阻塞1000毫秒
? ? ? B:線程11從上下文中讀取鍵為test類型string的值為空,阻塞14毫秒,再寫入鍵為test,類型為string的值14,后阻塞14毫秒
? ? ? C:線程11從上下文中讀取鍵為test類型string的值為14
? ? ? D:線程6從上下文中讀取鍵為test的string的值為1000
? ? ? E:兩個(gè)線程交替運(yùn)行,各自讀取和寫入的值互不影響
? ? ? 所以建議定義全局靜態(tài)變量的就省省吧,那樣線程不安全,危險(xiǎn)很大
3、有人會(huì)提到HttpContext
? ? ?確實(shí)HttpContext.Current.Items可以實(shí)現(xiàn)這樣的效果,但是HttpContext.Current并不是無處不在,非Web應(yīng)用程序?yàn)閚ull
? ? ?就算是Web項(xiàng)目也不能濫用HttpContext.Current,在異步線程里面該屬性也是null,不信的可以試試
? ? ?但是HttpContext.Current還是很有用的,我這里實(shí)現(xiàn)的AppContext就有調(diào)用HttpContext.Current,如果為null,再調(diào)用另一個(gè)更神秘的東西CallContext
? ? ?大家看一下實(shí)現(xiàn)代碼:
? ? ?在web程序中有異步操作會(huì)有線程切換,需要線程間復(fù)制上線文對(duì)象,使用HttpModule(以下代碼來自一個(gè)博客園大神,我?guī)缀鯖]改)
4、服務(wù)(配置)作用域
4.1 先看建模代碼
稍微解讀一下:
? ? ? ?A:Greet是用來打招呼,name對(duì)who發(fā)一個(gè)問候語(yǔ)
? ? ? ?B:Person明顯就是代表一個(gè)人,其中有一個(gè)Chindren屬性,代表從屬子對(duì)象(為了簡(jiǎn)化使用相同類型)
? ? ? ?C:Person有一個(gè)Sayer屬性,用來對(duì)其他"人"打招呼的
? ? ? ?D:從方法Greet(Greet sayer, Person person)可以看出,如果取不到sayer對(duì)象會(huì)打招呼失敗(提示sayer is miss)
? ? ? ?E:對(duì)另一個(gè)對(duì)象Great的時(shí)候會(huì)遍歷每個(gè)子對(duì)象分別對(duì)那個(gè)對(duì)象"問候"一下(這家的小孩還真有禮貌,大人問候誰(shuí),每個(gè)小孩都問候他)
4.2 再看測(cè)試代碼
也解讀一下:
? ? ? A:定義了a,a1,b及a的另一個(gè)子對(duì)象
? ? ? B: 其中只有a對(duì)象設(shè)置了Sayer屬性
? ? ? C:a對(duì)象Great了b(其中隱含a的所有子對(duì)象都對(duì)b進(jìn)行Greate),之后a1對(duì)象單獨(dú)Greate了一下b
4.3 看運(yùn)行結(jié)果
哈哈,看到結(jié)果是不是有點(diǎn)驚訝啊
? ? A:a對(duì)b的Hello是成功的很正常,但是a的兩個(gè)子對(duì)象也對(duì)b的Hello成功了
? ? B:更神奇的是,a1單獨(dú)對(duì)b的Hello缺是失敗的(不是繼承了父對(duì)象的屬性)
? ? C:這里對(duì)上線文又進(jìn)了一步,是作用域,只有a對(duì)b使用自己的Sayer屬性時(shí),其他對(duì)象(不一定是自己的子對(duì)象)也可以截獲Sayer的值,但是等a對(duì)象使用完畢后就回收了,其他人就用不了了
4.4 原理解析
? ??
? ? 這里有一個(gè)using的作用域,AppContext.CreateResource在上線文中注冊(cè)或者查找類型為Greate名字為A的,候選值為Sayer的對(duì)象,保存在resource.Entity中
4.5 來看一下實(shí)現(xiàn)的源代碼
?
? ? ? 哈哈,是不是有點(diǎn)復(fù)雜啊
? ? ?A:實(shí)現(xiàn)IDisposable以便使用using來控制作用域
? ? ?B:Dispose也不是簡(jiǎn)單的就把作用域的對(duì)象刪除,如果_needDispose為false不刪除對(duì)象(不是自己創(chuàng)建的對(duì)象無權(quán)刪除)
? ? ?C:除了刪除有的時(shí)候還要Restored(_needRestored為true),自己的作用域結(jié)束,把備份的_entity0還回去
? ? ?D:Init方法嘗試從作用域獲取對(duì)象并備份到_entity0,如果本次候選對(duì)象無效直接使用作用域已有對(duì)象,如果有效就覆蓋作用域(有_entity0備份能還原回來)
? ? ?E:是不是非常有意思,就像定義變量一樣,小作用域可以覆蓋上級(jí)作用的變量,離開小作用域,外面作用域的變量又可以使用了
5、作用域的作用
5.1 我特意開發(fā)這個(gè)功能是用來簡(jiǎn)化系統(tǒng)配置的
? ? ? 5.2 比如日志(含異常調(diào)試日志)幾乎是每個(gè)對(duì)象都需要的功能
如果每個(gè)對(duì)象都配置這些通用屬性,配置的工作量太大了,配置文件太亂了
? ? ? ? ? ?如果硬編碼寫死,那豈不就倒退到八百年前了
? ? ? ? ? ?并不是所有都不配,只把特殊需要的配置,如果需要日志在最外面配置(或者只初始化一個(gè)作用域),里面調(diào)用的子對(duì)象也都可以共享外層的配置(共享日志服務(wù))
? ? ? ? ? ?有人可能說沖突了怎么辦,用name隔離
6、應(yīng)用程序上下文緩存
? ??
? ? ? 這個(gè)緩存的作用域只能是當(dāng)前會(huì)話(線程或者Request),所以天生的線程安全(所以那個(gè)字典我都沒用ConcurrentDictionary)
? ? ? 有人可能要笑話我,緩存不都是分布式嗎?你那個(gè)緩存利用率太低了吧?
? ? ? 是的,你要說緩存利用率,確實(shí)不能和分布式比。但是要想到這個(gè)比session還session(不用清除下次請(qǐng)求重新初始化,也不用擔(dān)心被人杜撰(修改sessionId))的高速緩存(直接字典),自然也和session一樣不用擔(dān)心用戶數(shù)據(jù)串
? ? ? 用起來簡(jiǎn)單的不得了,直接New就可以使用,哪怕定義一個(gè)全局靜態(tài)變量都是“線程(會(huì)話)安全”的,也可以配置在容器里面放心使用
?
? ? ??測(cè)試項(xiàng)目下載
? ? ? 該組件暫時(shí)就先寫這么多吧。寫這篇文章的目的除了給大家分享自己的東西外,最主要的還是想得到博客園大神的指導(dǎo),因?yàn)榭蚣芤坏╅_始使用再做調(diào)整就很要命,其一希望框架能做的更通用更好用,大家一起使用。其二把可能的問題盡早的發(fā)現(xiàn),在正式使用之前更加完善。有些硬傷,比如接口、方法簽名定義等如果不合理推廣后也好修改,可能只能作為框架的缺陷存在了。接口一改,依賴這個(gè)接口的所有實(shí)現(xiàn)類都要改,很恐怖的。也是因?yàn)樵瓉黹_發(fā)匆忙的框架“缺陷”太多,我不得不下定決心開發(fā)新框架。
? ? ? 這么這么多天每天長(zhǎng)時(shí)間寫代碼,每天都寫得出汗,寫出了不少代碼,卻是今天下班后第一次調(diào)試,并且調(diào)試通過了一個(gè)我非常喜歡的上線文作用域組件(當(dāng)然還有優(yōu)化的地方)
? ? ? 下面簡(jiǎn)單介紹一下這個(gè)框架:
? ? ? 以下是項(xiàng)目解決方案截圖:
? ? A:第一張圖是解決方案,部分?jǐn)U展功能項(xiàng)目,這些需要很多人參與進(jìn)來完善
? ? B:后面的四張圖是框架主項(xiàng)目的截圖,大部分都是已經(jīng)開發(fā)完成還未測(cè)試的功能,其后是大量測(cè)試改bug和完善功能
? ? ? ? ?主框架及相關(guān)項(xiàng)目我會(huì)在這里系列里面逐個(gè)測(cè)試優(yōu)化后在發(fā)布出來,希望大家一起幫忙看一下,提供意見和建議
? ? C:主框架本身并不力求解決所有方法,而是定義一些通用功能邏輯的接口,對(duì)部分接口提供默認(rèn)實(shí)現(xiàn)及部分“設(shè)計(jì)模式”功能,其他功能在其他項(xiàng)目中再擴(kuò)展實(shí)現(xiàn)
? ? D:主框架不含對(duì)具體哪種數(shù)據(jù)或者哪種ORM工具的調(diào)用和不含具體開源外部日志組件和容器等調(diào)用
? ? E:該框架并不是要推翻系統(tǒng)的東西,而是要整合,要可擴(kuò)展,給程序員帶來更多便利和選擇
? ? F:總之就是主框架抽象接口、實(shí)現(xiàn)非常通用的部分功能,盡量少引用
? ? G:其他功能都期望按主框架的接口來開發(fā),以便方便集成到主框架,或者其他模塊
原文地址:http://www.cnblogs.com/xiangji/p/5415080.html
.NET社區(qū)新聞,深度好文,微信中搜索dotNET跨平臺(tái)或掃描二維碼關(guān)注
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的Asp.net 面向接口框架之应用程序上下文作用域组件的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HoloLens开发手记-硬件细节 Ha
- 下一篇: 我是这样入侵 Hacking Team