有一小段時(shí)間沒(méi)有持續(xù)升級(jí)ABP框架了,最近就因應(yīng)客戶的需要,把ABP框架進(jìn)行全面的更新,由于我們應(yīng)用的ABP框架,基礎(chǔ)部分還是會(huì)使用官方的內(nèi)容,因此升級(jí)的時(shí)候需要把官方基礎(chǔ)ABP的DLL進(jìn)行全面的更新,以及對(duì)應(yīng)的引用DLL也同步更新才行。不過(guò)在升級(jí)過(guò)程中還是很多奇奇怪怪的問(wèn)題,本篇隨筆針對(duì)出現(xiàn)的情況進(jìn)行一系列的總結(jié),以便后面有一個(gè)對(duì)照參考吧。
1、最新案例源碼和NugGet程序包更新
ABP官方的基礎(chǔ)模塊更新速度還是很快的,一段時(shí)間過(guò)去,就跳過(guò)了幾個(gè)版本號(hào),我是在舊版本的基礎(chǔ)上進(jìn)行手動(dòng)的NugGet更新,但是基于VS的Nugget總是更新卡頓,不知不覺(jué)就沒(méi)有反應(yīng)了,嚴(yán)重影響開(kāi)發(fā)的效率。因此先從官方下載的Demo案例中把相關(guān)部分源碼進(jìn)行更新。
官方的案例源碼下載地址是:https://aspnetboilerplate.com/Templates
1)最新案例源碼結(jié)構(gòu)和部分內(nèi)容調(diào)整
我們從其中下載對(duì)應(yīng)的源碼,然后根據(jù)項(xiàng)目結(jié)構(gòu)中的對(duì)應(yīng)源碼文件,使用Beyond Compare對(duì)比文件進(jìn)行文件逐一對(duì)比,原則上除了個(gè)人擴(kuò)展的部分,都以官方的源碼做法為準(zhǔn)即可。
目前ABP官方最新的DLL版本是5.3.0,可以下載的Demo版本是5.2.0,它們應(yīng)該差別不大。下載下來(lái)的Aspnet-core部分的源碼結(jié)構(gòu)如下所示。
而我們的ABP框架是在這個(gè)基礎(chǔ)上進(jìn)行一定的結(jié)構(gòu)優(yōu)化,以更加方便快速的開(kāi)發(fā),以及結(jié)合代碼生成工具進(jìn)行快速的使用。
我們的VS項(xiàng)目結(jié)構(gòu) 如下所示。
以上是VS里面解決方案的項(xiàng)目結(jié)構(gòu),我根據(jù)項(xiàng)目之間的關(guān)系,整理了一個(gè)架構(gòu)的圖形,如下所示。
上圖中,其中橘紅色部分就是我們?yōu)楦鱾€(gè)層添加的類或者接口,分層上的序號(hào)是我們需要逐步處理的內(nèi)容。
應(yīng)用服務(wù)層是整個(gè)ABP框架的靈魂所在,對(duì)內(nèi)協(xié)同倉(cāng)儲(chǔ)對(duì)象實(shí)現(xiàn)數(shù)據(jù)的處理,對(duì)外配合Web.Core、Web.Host項(xiàng)目提供Web API的服務(wù),而Web.Core、Web.Host項(xiàng)目幾乎不需要進(jìn)行修改,因此應(yīng)用服務(wù)層就是一個(gè)非常關(guān)鍵的部分,需要考慮對(duì)用戶登錄的驗(yàn)證、接口權(quán)限的認(rèn)證、以及對(duì)審計(jì)日志的記錄處理,以及異常的跟蹤和傳遞,基本上應(yīng)用服務(wù)層就是一個(gè)大內(nèi)總管的角色,重要性不言而喻。
回顧了解一下我們改造過(guò)的ABP開(kāi)發(fā)框架的結(jié)構(gòu)后,我們返回到版本升級(jí)的主體上來(lái)介紹。
目前我把VS的版本升級(jí)到最新,其.net framework支持4.8, 并單獨(dú)安裝了dotnetcore最新版本3.1,因此環(huán)境是最新的,而基礎(chǔ)的ABP 5.3.0也是采用了.net core3.1。
對(duì)比源碼,我們可以發(fā)現(xiàn),Web.Host和Web.Core項(xiàng)目里面已經(jīng)有所差異,IHostingEnvironment已經(jīng)被拋棄使用,而采用dotnetcore最新對(duì)象IWebHostEnvironment來(lái)替代了。
替換最新源碼為
因此Web.Host項(xiàng)目中的Module類也進(jìn)行了調(diào)整。
相對(duì)應(yīng)的Web.Core項(xiàng)目里面的Module也同時(shí)進(jìn)行調(diào)整了。
2)NugGet程序包更新
Nugget程序包的更新,原則上可以選擇單個(gè)項(xiàng)目進(jìn)行更新,或者選擇整個(gè)解決方案進(jìn)行程序包的更新,前者可能相應(yīng)速度快一些,后者由于解決方案項(xiàng)目數(shù)量問(wèn)題,可能會(huì)較慢。
我早期的基礎(chǔ)ABP版本是4.9,因此想一次性整個(gè)的解決方案的程序包進(jìn)行更新,不過(guò)嘗試多次,花了幾個(gè)小時(shí),都無(wú)法順利進(jìn)行項(xiàng)目的全部更新,于是單個(gè)項(xiàng)目進(jìn)行更新,也非常慢。
于是也通過(guò)推薦采用Nugget最新地址進(jìn)行更新,如下設(shè)置更新源。
在程序包源中添加:https://api.nuget.org/v3/index.json
響應(yīng)速度相對(duì)快了一些,沒(méi)有不經(jīng)常的出問(wèn)題了。
我們?nèi)绻枰獑为?dú)更新某個(gè)項(xiàng)目的程序包,那么需要選擇項(xiàng)目,選擇【管理Nugget程序包】進(jìn)入界面更新即可。如下界面所示。
一般情況下,我們推薦對(duì)整個(gè)解決方案進(jìn)行全面的程序包更新,如下選擇解決方案,然后進(jìn)入對(duì)應(yīng)Nugget程序包管理界面更新即可。
這樣的全部更新解決方案的程序包,如果能夠順利完成,那是皆大歡喜,不過(guò)可能會(huì)稍微慢一些。如果不行,只有逐個(gè)更新程序包了。
我之前選擇這樣的方式更新的時(shí)候,總是有一兩個(gè)程序包更新出錯(cuò),因此只有使用npm 控制臺(tái)進(jìn)行單獨(dú)的升級(jí)了。
2、ABP框架基類封裝接口命名調(diào)整
在更新ABP基礎(chǔ)模塊的時(shí)候,發(fā)現(xiàn)ABP的基礎(chǔ)接口全部調(diào)整了命名,如原來(lái)的Get變?yōu)镚etAsync,GetAll變?yōu)?GetAllAsync,Delete變?yōu)榱薉eleteAsync,Update變?yōu)榱薝pdateAsync,Create變?yōu)榱薈reateAsync。
也就是說(shuō),他們?nèi)坎捎昧水惒矫Q的命名規(guī)則,在異步方法后面全部加上了Async作為標(biāo)識(shí)。
我在之前模塊介紹過(guò)ABP框架的基礎(chǔ)接口。IAsyncCrudAppService定義了幾個(gè)通用的創(chuàng)建、更新、刪除、獲取單個(gè)對(duì)象和獲取所有對(duì)象列表的接口,接口定義如下所示。
namespace Abp.Application.Services
{
public interface IAsyncCrudAppService<TEntityDto, TPrimaryKey, in TGetAllInput, in TCreateInput, in TUpdateInput, in TGetInput, in TDeleteInput> : IApplicationService, ITransientDependency
where TEntityDto : IEntityDto<TPrimaryKey>
where TUpdateInput : IEntityDto<TPrimaryKey>
where TGetInput : IEntityDto<TPrimaryKey>
where TDeleteInput : IEntityDto<TPrimaryKey>
{
Task<TEntityDto> Create(TCreateInput input);
Task Delete(TDeleteInput input);
Task<TEntityDto> Get(TGetInput input);
Task<PagedResultDto<TEntityDto>> GetAll(TGetAllInput input);
Task<TEntityDto> Update(TUpdateInput input);
}
}
現(xiàn)在這些接口全部調(diào)整如下所示了。
namespace Abp.Application.Services
{
public interface IAsyncCrudAppService<TEntityDto, TPrimaryKey, in TGetAllInput, in TCreateInput, in TUpdateInput, in TGetInput, in TDeleteInput> : IApplicationService, ITransientDependency
where TEntityDto : IEntityDto<TPrimaryKey>
where TUpdateInput : IEntityDto<TPrimaryKey>
where TGetInput : IEntityDto<TPrimaryKey>
where TDeleteInput : IEntityDto<TPrimaryKey>
{
Task<TEntityDto> CreateAsync(TCreateInput input);
Task DeleteAsync(TDeleteInput input);
Task<PagedResultDto<TEntityDto>> GetAllAsync(TGetAllInput input);
Task<TEntityDto> GetAsync(TGetInput input);
Task<TEntityDto> UpdateAsync(TUpdateInput input);
}
}
那么這些我們都必須隨著ABP框架的調(diào)整也同時(shí)進(jìn)行接口和對(duì)應(yīng)類實(shí)現(xiàn)的調(diào)整了。
例如對(duì)應(yīng)的異步ApplicationService服務(wù)的基類封裝,我們也需要調(diào)整對(duì)應(yīng)的異步接口實(shí)現(xiàn)。
針對(duì)遠(yuǎn)程調(diào)用的ApiCaller接口和實(shí)現(xiàn),我們也需要進(jìn)行命名方面的統(tǒng)一調(diào)整,這樣才能順利進(jìn)行異步接口的調(diào)用
我在之前隨筆《ABP開(kāi)發(fā)框架前后端開(kāi)發(fā)系列---(10)Web API調(diào)用類的簡(jiǎn)化處理》有針對(duì)API調(diào)用層的簡(jiǎn)化處理做了說(shuō)明,我們所有的API調(diào)用,基本都是通過(guò)統(tǒng)一的一個(gè)函數(shù)進(jìn)行調(diào)用的。
統(tǒng)一調(diào)用處理的方法名稱是DoActionAsync。
雖然由于前面介紹了應(yīng)用服務(wù)層的接口很多接口增加了Async的后綴字符,但是客戶端通過(guò)URL調(diào)用,這個(gè)Async是不需要的,也就是需要移除,我們之前組裝的URL地址是根據(jù)函數(shù)名稱,那么函數(shù)名稱需要移除這個(gè)后綴的Async字樣了。
這樣系統(tǒng)就順利跑起來(lái)了。服務(wù)端界面如下所示。
我們啟動(dòng)Winform客戶端,界面如下所示。
登陸啟動(dòng)后主體界面如下所示