.Net Core应用框架Util介绍(四)
上篇介紹了Util Angular Demo的目錄結(jié)構(gòu)和運(yùn)行機(jī)制,本文介紹Util封裝Angular的基本手法及背后的動(dòng)機(jī)。
Angular應(yīng)用由Ts和Html兩部分構(gòu)成,本文介紹第一部分。
Angular Ts的封裝
Ts是Angular的代碼部分,用于編寫頁(yè)面邏輯。
依賴注入( Dependency Injection )
Ioc(Inversion of Control)已經(jīng)成為.Net Core服務(wù)端編程的標(biāo)配,Ioc解耦了類和依賴類之間的創(chuàng)建關(guān)系,讓你開發(fā)出低耦合高內(nèi)聚的系統(tǒng)。
有了Ioc,你就可以面向抽象編程,注入依賴的接口,直接使用即可,而不用關(guān)心這個(gè)對(duì)象是如何創(chuàng)建出來(lái)的,也不用關(guān)心它具體是什么類型。
Angular革命性的把Ioc引入到客戶端腳本編程,從這里也可以看出,Angular實(shí)際上更適合具有服務(wù)端編程經(jīng)驗(yàn)的開發(fā)人員。
依賴注入是Ioc的一種使用模式,最常見的是構(gòu)造方法依賴注入,將依賴對(duì)象定義在構(gòu)造方法參數(shù)上,運(yùn)行時(shí),Ioc框架會(huì)把依賴對(duì)象“推送”進(jìn)來(lái),從使用的角度看,業(yè)務(wù)代碼并不知道Ioc的存在,業(yè)務(wù)代碼未與Ioc框架耦合,極易測(cè)試,代碼也極度清爽,這一度讓依賴注入成為Ioc的代名詞,也是Ioc的推薦用法。
當(dāng)在Angular中使用依賴注入,有沒(méi)有什么缺陷呢?下面來(lái)看個(gè)例子。
?
這段代碼需要發(fā)送Http請(qǐng)求,所以從構(gòu)造方法注入了Http。
你必須要精確的知道Angular的哪個(gè)類提供了Http服務(wù),并且需要知道這個(gè)類在什么路徑下。并不是每個(gè)類都像Http這么簡(jiǎn)短易記,這增加了大腦的負(fù)荷。
對(duì)于專業(yè)Angular前端人員,這算不上什么缺陷,不過(guò)它確實(shí)增加了小團(tuán)隊(duì)使用Angular的學(xué)習(xí)成本。
對(duì)于這個(gè)例子,哪怕你知道注入Http類,也清楚它的路徑,但可能仍然引入了未知的Bug。Angular還提供了一個(gè)叫HttpClient的類,它在@angular/common/http路徑下,HttpClient提供了攔截等高級(jí)機(jī)制,用來(lái)取代@angular/http包。如果你團(tuán)隊(duì)的一部分人使用HttpClient,并對(duì)Http進(jìn)行了攔截,比如設(shè)置全局Token,另一部分人使用Http類發(fā)送請(qǐng)求,就會(huì)導(dǎo)致潛在的BUG。
現(xiàn)在你清楚了對(duì)Angular API進(jìn)行封裝的必要性。
封裝是一種隱藏實(shí)現(xiàn)細(xì)節(jié)的手段,封裝以后,你的注意力將從Angular Api轉(zhuǎn)移到自己的業(yè)務(wù)上。
對(duì)于Http請(qǐng)求,理想的API可能長(zhǎng)成這樣。?
?
首先,你并沒(méi)有從@angular/common/http引入HttpClient,更沒(méi)有在構(gòu)造方法上注入它。這解決了需要記憶API的問(wèn)題。
其次,你并不清楚util.http封裝的具體類型是什么,這統(tǒng)一了團(tuán)隊(duì)的API調(diào)用,也方便你在未來(lái)需要更換實(shí)現(xiàn)時(shí)不至于挨處查找。
我在前幾年使用EasyUi時(shí)也封裝了這樣的Helper,通過(guò)直接引用并簡(jiǎn)單包裝就完成了任務(wù)。?
Helper往往表現(xiàn)為靜態(tài)方法,面對(duì)Angular的Ioc體系,封裝Helper變得很棘手,如何把需要的對(duì)象依賴注入到Helper靜態(tài)方法中呢??
你如果直接import引入Angular API,這樣封裝出來(lái)的Helper行為上可能是錯(cuò)的,比如HttpClient的攔截機(jī)制,import創(chuàng)建的HttpClient實(shí)例脫離了Ioc框架,這將導(dǎo)致攔截失效。?
一種辦法是避開靜態(tài)方法,你可以注入U(xiǎn)til類,這樣就可以拿到Angular Ioc容器中的相關(guān)實(shí)例了,這確實(shí)是個(gè)辦法。?
不過(guò)你如果希望使用靜態(tài)方法,有沒(méi)有辦法現(xiàn)實(shí)呢??
服務(wù)定位器( Service Locator )
依賴注入威名遠(yuǎn)播,以至于很多人并不清楚它還有個(gè)同父異母的弟弟 —— 服務(wù)定位器。
服務(wù)定位器是Ioc的另一種使用模式,你可以在代碼中主動(dòng)調(diào)用Ioc容器方法“拉取”依賴對(duì)象,這會(huì)導(dǎo)致你的代碼與Ioc框架耦合,讓代碼也更難測(cè)試。
服務(wù)定位器儼然成為一種反模式,那么它是否已經(jīng)一無(wú)是處了呢?
我發(fā)現(xiàn)在大多數(shù)情況下,并不需要服務(wù)定位器,但在某些情況下,它卻非常有用。
哪種情況需要服務(wù)定位器?當(dāng)你無(wú)法使用依賴注入時(shí),就該它出手了。
比如靜態(tài)方法,你就無(wú)法使用依賴注入,通過(guò)服務(wù)定位器方式仍然可以訪問(wèn)Ioc,這對(duì)于封裝框架Helper有非常重大的意義,我會(huì)在本系列后續(xù)文章介紹服務(wù)定位器在.Net Core服務(wù)端封裝上的應(yīng)用。?
Util Angular Helper大量使用了服務(wù)定位器,以更簡(jiǎn)單的方式提供常用API。?
Util Angular Helper介紹
Helper
它位于/Typings/util/common/helper.ts,包含一些常用操作,比如空值判斷,類型轉(zhuǎn)換等,helper.ts內(nèi)部將操作委托給lodash等第三方j(luò)s庫(kù)。
IocHelper
?
它位于/Typings/util/angular/ioc-helper.ts。
IocHelper內(nèi)部保存了Angular Ioc容器實(shí)例,以方便其它Helper以服務(wù)定位器的方式來(lái)訪問(wèn)Ioc容器。
由于Angular Ioc具有分級(jí)特性,所以保存了模塊級(jí)和組件級(jí)兩種容器,對(duì)于獲取路由參數(shù)等操作,必須從組件容器獲取實(shí)例,否則將導(dǎo)致錯(cuò)誤的行為。
在什么位置設(shè)置Angular Ioc容器呢?
模塊級(jí)容器在AppModule根模塊中設(shè)置,組件級(jí)容器需要在每個(gè)組件設(shè)置,這造成了不便,尚未找到更優(yōu)雅的方式。
?
下面演示了IocHelper的用法。
let client = util.ioc.get<HttpClient>(HttpClient);HttpHelper
對(duì)于業(yè)務(wù)操作,使用得最頻繁的Angular Api莫過(guò)于發(fā)送Http請(qǐng)求,從服務(wù)端獲取Json數(shù)據(jù),或?qū)⒈韱螖?shù)據(jù)傳遞給服務(wù)端處理。
Util通過(guò)HttpHelper,WebApi,Form三個(gè)Helper從不同層次對(duì)Http操作進(jìn)行了封裝。
HttpHelper位于/Typings/util/angular/http-helper.ts,對(duì)Angular?HttpClient進(jìn)行了簡(jiǎn)單包裝,提供原始Http操作。
Util盡量提供同步Api,使用回調(diào)函數(shù),而不是Rx的Observable或異步Promise,這樣團(tuán)隊(duì)成員只要具備JQuery經(jīng)驗(yàn)就能開發(fā),降低了團(tuán)隊(duì)的學(xué)習(xí)成本。?
在絕大多數(shù)情況下,你并不需要調(diào)用HttpHelper,WebApi和Form操作類會(huì)提供更多默認(rèn)行為。
WebApi?
在發(fā)送Http請(qǐng)求時(shí),你通常需要處理異常。?
異??煞譃?strong>Http異常和業(yè)務(wù)異常兩類。?
Http異常是未成功的Http響應(yīng),比如Http狀態(tài)碼為500的服務(wù)器內(nèi)部錯(cuò)誤。Http異常通常和業(yè)務(wù)無(wú)關(guān),所以每次發(fā)送請(qǐng)求設(shè)置Http異常處理是枯燥乏味的。?
另一方面,Http返回200成功信號(hào)并不代表業(yè)務(wù)執(zhí)行成功,所以不應(yīng)該通過(guò)Http狀態(tài)碼來(lái)識(shí)別業(yè)務(wù)是否成功完成。?
通過(guò)客戶端和服務(wù)端約定標(biāo)準(zhǔn)通信格式可以簡(jiǎn)化異常處理。?
先來(lái)看客戶端結(jié)果類型。
?
?
下面是服務(wù)端結(jié)果類型。
?
?
WebApi操作類位于/Typings/util/common/webapi.ts,它在HttpHelper的基礎(chǔ)上,設(shè)置了默認(rèn)的Http異常處理,將Http異常輸出到瀏覽器控制臺(tái),以方便排錯(cuò),另外將服務(wù)端返回結(jié)果轉(zhuǎn)換為客戶端標(biāo)準(zhǔn)結(jié)果類型。?
下面展示了WebApi操作類的用法,handler方法是成功處理函數(shù),你不用進(jìn)行任何狀態(tài)判斷,WebApi內(nèi)部已經(jīng)處理過(guò)了。注意result參數(shù)并不是我們定義的標(biāo)準(zhǔn)Result類型,而是Result的data屬性,也就是實(shí)際業(yè)務(wù)類型,前后端標(biāo)準(zhǔn)通信格式被封裝起來(lái)。
Form?
對(duì)于管理后臺(tái),大多為表單操作,所以我們對(duì)表單需要特殊關(guān)照。?
Form操作類位于/Typings/util/common/form.ts,它內(nèi)置了一些表單常見操作。?
當(dāng)表單提交失敗,通常會(huì)提示一個(gè)錯(cuò)誤消息,以指示用戶修正錯(cuò)誤。
?
錯(cuò)誤提示是Form操作類的默認(rèn)設(shè)置,你也可以取消它。
?
有時(shí)候,你希望在提交表單前先確認(rèn)一下。
?
?
通過(guò)設(shè)置一個(gè)屬性就完成任務(wù)是不是很爽??
?
Form操作類還包含很多有用的功能,下面是它的參數(shù)定義。
?Form操作類參數(shù)
Form操作類建立在WebApi操作類之上,而WebApi操作類建立上HttpHelper之上,通過(guò)層層包裝,讓Http請(qǐng)求變得更加簡(jiǎn)單易用。
RouterHelper?
Angular提供了路由機(jī)制,路由訪問(wèn)是僅次于Http請(qǐng)求的操作。
通常需要從路由中獲取參數(shù)。
RouterHelper用于操作路由,位于/Typings/util/angular/router-helper.ts,在內(nèi)部使用服務(wù)定位器訪問(wèn)ActivatedRoute,簡(jiǎn)化了路由訪問(wèn)。
Message?
表單操作經(jīng)常需要彈出各類消息框,比如成功提示框,錯(cuò)誤提示框,確認(rèn)提示框等。
Message操作類集成封裝了PrimeNg和Angular?Material的消息框,它位于/Typings/util/common/message.ts。
?
下面彈出了一個(gè)錯(cuò)誤消息框。
util.message.error("哈哈");Dialog
Dialog操作類封裝了Material彈出層,位于/Typings/util/common/dialog.ts。
?
?
下面演示了將外部網(wǎng)頁(yè)加載到iframe中。
?
加載業(yè)務(wù)組件應(yīng)使用dialogComponent屬性。
?
Util Angular CRUD基類介紹?
Js是一種弱類型語(yǔ)言,通過(guò)原型鏈和閉包可以模擬出面向?qū)ο蟮奶卣?#xff0c;雖然看過(guò)一些文章說(shuō)Js其實(shí)比C#這樣的面向?qū)ο笳Z(yǔ)言更加OO,不過(guò)我始終沒(méi)有感覺出來(lái),這或許是專業(yè)水平和我這種半吊子水平的區(qū)別所在吧。
前幾年我對(duì)Js的封裝僅限于Helper或組件,服務(wù)端摸索出來(lái)的經(jīng)驗(yàn)很難應(yīng)用到Js,雖然能模擬出我想達(dá)到的效果,但卻不是那么直觀。
雖然有人常說(shuō)語(yǔ)言不是問(wèn)題,語(yǔ)法更不是問(wèn)題,但那指的是高手,在尚未達(dá)到高手境界以前,我們需要更優(yōu)雅的語(yǔ)法糖,這使你寫起來(lái)心情舒暢,開發(fā)業(yè)務(wù)效率倍增。
Typescript提供了強(qiáng)大的語(yǔ)法糖,包括面向?qū)ο蠡菊Z(yǔ)法,泛型,lambda表達(dá)式等,Angular則提供了Ioc等服務(wù)端才具備的特性,這對(duì)于具備服務(wù)端架構(gòu)設(shè)計(jì)經(jīng)驗(yàn)的朋友,無(wú)疑是把利器。
對(duì)于簡(jiǎn)單Crud操作,來(lái)回就那幾句重復(fù)代碼,能否在Angular開發(fā)中像C#一樣封裝個(gè)基類呢?
有了Typescript和Angular,這是非常輕松的任務(wù)。
TableQueryComponentBase?
對(duì)于簡(jiǎn)單Crud,通常在主界面放一個(gè)表格,并提供Crud操作。
TableQueryComponentBase是表格查詢基類,它提供了從表格刪除行,刷新表格,搜索等功能,位于/Typings/util/base/table-query-component-base.ts。
有了基類,業(yè)務(wù)組件將變得十分干凈。
?
Angular官方推薦將業(yè)務(wù)操作從組件分離,使用服務(wù)的形式依賴注入到組件,這讓你的設(shè)計(jì)更加內(nèi)聚。
不過(guò)我沒(méi)有機(jī)械的執(zhí)行這一指南,僅在業(yè)務(wù)操作變得復(fù)雜時(shí)使用這種方式,在更多的簡(jiǎn)單場(chǎng)景,我會(huì)把數(shù)據(jù)操作直接內(nèi)置到組件中。
EditComponentBase
EditComponentBase是Crud編輯基類,除了提交表單以外,它還能從路由取得Id并從服務(wù)端加載數(shù)據(jù),位于/Typings/util/base/edit-component-base.ts。
?
?
ApplicationEditComponent示例類重寫了loadById和submit方法,刪除掉同樣可以工作,當(dāng)你有特殊要求的時(shí)候進(jìn)行重寫。
FormComponentBase?
一個(gè)常見的需求,當(dāng)表單已經(jīng)被更改時(shí),跳轉(zhuǎn)頁(yè)面需要提示用戶保存。
FormComponentBase是表單基類,位于/Typings/util/base/form-component-base.ts,它提供了表單變更值檢查方法。
?
TreeTableQueryComponentBase?與?TreeEditComponentBase
與TableQueryComponentBase和EditComponentBase類似,這兩兄弟也是用來(lái)支持簡(jiǎn)單Crud操作的,不過(guò)它們用來(lái)支持樹型關(guān)系。
繼承基類,收工,不要在簡(jiǎn)單Crud上浪費(fèi)過(guò)多時(shí)間。
?
?
Util Demo的role示例演示了樹型Crud的用法。
小結(jié)
本文簡(jiǎn)單介紹了Util Angular Helper的封裝,使用服務(wù)定位器封裝成鏈?zhǔn)?#xff0c;所有helper都內(nèi)聚在util這個(gè)命名空間下,這大幅提升了Angular的易用性,對(duì)于常用功能,不用記憶任何API,憑借一點(diǎn)模糊的印象就能夠完成任務(wù)。
另外介紹了為簡(jiǎn)化Crud提供的基類,這和服務(wù)端Crud封裝很相似,得益于Typescript和Angular所提供的強(qiáng)大語(yǔ)法糖。
未完待續(xù),Angular 組件封裝及TagHelper將在下篇介紹。
寫文需要?jiǎng)恿?#xff0c;請(qǐng)大家多多支持,點(diǎn)下推薦,Github點(diǎn)下星星。
Util應(yīng)用框架交流一群: 24791014
Util應(yīng)用框架地址:https://github.com/dotnetcore/util
相關(guān)文章:
.Net Core應(yīng)用框架Util介紹(一)
.Net Core應(yīng)用框架Util介紹(二)
.Net Core應(yīng)用框架Util介紹(三)
原文地址:?https://www.cnblogs.com/xiadao521/p/Util-Introduction-4.html
.NET社區(qū)新聞,深度好文,歡迎訪問(wèn)公眾號(hào)文章匯總 http://www.csharpkit.com
總結(jié)
以上是生活随笔為你收集整理的.Net Core应用框架Util介绍(四)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 中国开源年会 COSCon 2018 今
- 下一篇: 使用 dotTrace 分析 .NET