接觸ABP框架有一段時間了,也遇到了一些問題,看了官網文檔,但是或許是看的不夠細致的原因,實際開發中還是遇到了一些問題,耗費了時間去處理,回頭一看,原來文檔中早已提及。
開發環境:ABP+MPA模式+Asp.Net Core
一、異常信息處理
猶如ABP官網文檔所介紹的,ABP已經幫我們把異常這塊處理的很完善了,我們要做的就是利用好ABP處理異常的功能。
ABP提供了直接將應用層對外服務的功能,通過ABP運行時所創建的動態API層,我們可以使用js方法去直接調用應用層服務,當然直接訪問控制器下的方法並沒有被舍棄。
在ABP內自動封裝好了一批處理異常的類,配合着這些異常類的使用,ABP在前端也封裝了一些方法,方便我們處理異常信息,同時我們也可以改造前端在展示異常的方式,ABP封裝的是使用Message API展示異常信息並使用的是sweetAlert插件,ABP前端js中提供了方式可以使得我們阻止默認的展示,進而使用自定義的展示插件和展示方式。
在封裝的類中,UserFriendlyException是對用戶友好的,對於一些操作可能產生的問題,可以通過拋出UserFriendlyException直接展示給用戶看,而對於其它異常,前端會將詳細信息的隱藏,因為用戶並不會關心具體報錯原因,只知道是報錯了。在代碼中,有些操作可能需要我們進行判斷,然后反饋給用戶,以便提示用戶更改相關數據。
[AbpAuthorize(AppPermissions.Pages_Standard_ItemCode_Create)] private async Task CreateItemCodeAsync(CreateOrUpdateItemCodeInput input) { var itemCode = ObjectMapper.Map<ItemCode>(input.ItemCode); itemCode.Id = itemCode.CreateUniqueItemCode(); var existedItemCode = await _itemCodeRepository.FirstOrDefaultAsync(t => t.Id.Equals(itemCode.Id)); if (existedItemCode != null) { throw new UserFriendlyException(L("該檢測項目已經存在.")); } await _itemCodeRepository.InsertAsync(itemCode); }
如上,在做一個操作前,可能需要判斷是否有相同的記錄,如果有,需要提示給用戶,通過直接拋出UserFriendlyException,在控制器內或在應用層拋出異常都行,可以將信息直接呈現給用戶,但是需要注意的是有一些條件限制,需要滿足相關的條件才能獲取到該錯誤信息,否則很有可能拿到如下結果或是英文錯誤:"An error has occurred! Error detail not sent by server."
二、展示異常信息的方式
在ABP文檔中,專門有一篇文章是處理異常的,https://aspnetboilerplate.com/Pages/Documents/Handling-Exceptions。
1、非Ajax請求,則直接展示錯誤頁,此處模擬拋出兩種異常類型,然后在界面中看異常信息。
public IActionResult Index() { //throw new System.Exception("error message"); throw new UserFriendlyException("error message"); }
如果是拋出的異常不是UserFriendlyException類型,則錯誤頁中展示的信息可能會被隱藏,展示的是描述性的,只需要知道內部出錯就行。
當拋出的是UserFriendlyException類型時,可以看到一些直觀的錯誤信息。
當然,可以在WebCoreModule模塊的預加載方法中啟動展示詳細信息。
Configuration.Modules.AbpWebCommon().SendAllExceptionsToClients = true;
比如開啟后,可以看到如下具體錯誤信息,雖然這些信息對於用戶來講是沒有什么價值的。
2、Ajax請求中,跟着官方給定的文檔走一遍是沒有錯的,就怕一些小細節沒有把握到,然后產生大問題,Ajax形式的調用並結合WrapResult特性使用后,在出現異常時,會將數據封裝成如下簡約形式。
{ "targetUrl": null, "result": null, "success": false, "error": { "message": "An internal error occurred during your request!", "details": "..." }, "unAuthorizedRequest": false }
這里需要注意一個關鍵的一點,是調用控制器下某個方法的返回類型,必須要object、JsonResult和ObjectResult類型,否則將會頁面錯誤框中看不到具體的錯誤信息。
從開發習慣來講,控制器中的方法返回值類型,我喜歡寫如下的格式(錯誤用法),直接使用IActionResult很方便,但是也會有麻煩,
[HttpPost] public async Task<IActionResult> CreateXXX([FromBody]ItemCodeViewModel itemCodeViewModel) {
//do something...return Json(xxx)); }
當在中拋出異常或是方法內調用應用層服務內拋出異常時,界面上的方法總是無法獲取到異常信息,通過查看瀏覽器內響應的內容總是只會有錯誤頁響應回來,而頁面內只能看到"An error has occurred! Error detail not sent by server."
具體原因就是這個方法的返回值不符合ABP文檔給定的要求,而這些細節,在初看文檔或是二次看文檔中都沒有發現它,細節很重要!!!。
3、直接通過動態Api層請求應用層服務,這種情形下,當應用層拋出異常時,會將異常信息經WrapResult封裝,在前端獲取的錯誤信息便是直接封裝完畢的錯誤信息,然后再經處理展示到頁面中。
2019-04-27,望技術有成后能回來看見自己的腳步