ABP Changing Httpcode status

来源:https://www.cnblogs.com/dogtwo0214/archive/2018/12/26/10178290.html
-Advertisement-
Play Games

小弟初來乍到,分享一些工作學習中遇到的問題和解決方式,如有不准確或是有錯誤的地方,希望不吝賜教,謝過了。 --Dogtwo 起因: ABP 中異常處理的思路是很清晰的。一共五種類型的異常類。 AbpInitializationException用於封裝ABP初始化過程中出現的異常,只要拋出AbpIn ...


  小弟初來乍到,分享一些工作學習中遇到的問題和解決方式,如有不准確或是有錯誤的地方,希望不吝賜教,謝過了。  --Dogtwo

 

起因:
ABP 中異常處理的思路是很清晰的。一共五種類型的異常類。

AbpInitializationException用於封裝ABP初始化過程中出現的異常,只要拋出AbpInitializationException異常就可以,無須做額外處理。這類異常往往是需要維護人員介入分析的。

其他四個異常都在AbpController中被集中處理,處理分為兩步:一,通過EventBus觸發異常事件,相應的異常處理函數則處理異常。二,針對AbpValidationException,UserFriendlyException和AbpAuthorizationException異常,Abp會將異常信息轉換為ErrorInfo,並以view或Json的形式返回給客戶端。
(以上內容摘自 HK Zhand大大的博客

我們應使用UserFriendlyException來包裝我們自定義的異常,但UserFriendlyException拋出的異常存在一個問題:無法指定HttpStatus code,這樣前端收到的response中HttpStatus code均為500。對一部分前端語言或框架來說,這個狀態碼難以處理或不便於處理,因為約定5xx指示伺服器異常,不應再由前端進行Handle。

所以,我們希望更改Response中的HttpStatus code。

思路很簡單,我們利用filter去攔截異常,判斷其類型,若為我們自定義的異常則更改HttpStatus code。

Filter部分代碼

 1 public class MyExceptionFilter : IExceptionFilter
 2 {
 3     public ILogger Logger { get; set; }
 4 
 5     public MyExceptionFilter()
 6     {
 7         Logger = NullLogger.Instance;
 8     }
 9 
10     public void OnException(ExceptionContext context)
11     {
12         if (!(context.Exception is MyException))
13         {
14             return;
15         }
16 
17         HandleAndWrapException(context);
18     }
19 
20     private void HandleAndWrapException(ExceptionContext context)
21     {
22         context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
23 
24         var myException = (MyException)context.Exception;
25 
26         context.Result = new ObjectResult(
27           new AjaxResponse(
28             new ErrorInfo(myException.ErrorCode, myException.Message)
29         )    
30      );
31 
32         LogHelper.LogException(Logger, context.Exception);
33 
34         context.Exception = null; //Handled!
35     }
36 }            

然後再StartUp文件中添加filter

1 services.Configure(mvcOptions =>
2 {
3     mvcOptions.Filters.AddService(typeof(MyExceptionFilter ));
4 });

 

運行發現,filter並不能catch住我們拋出的異常,甚至OnException方法體都沒進入。
原來,ABP本身實現了幾個filter,包括Authorization Filter, Audit Action Filter, Validation Action Filter, Unit of Work Action Filter, Exception Filter和Result Filter.
造成我們的自定義filter無法正常執行的原因就是Exception Filter.

ABP官方文檔介紹為:
AbpExceptionFilter is used to handle exceptions thrown from controller actions. It handles and logs exceptions and returns a wrapped response to the client.

This only handles object results, and not view results. Actions returning any object, JsonResult or ObjectResult will be handled. Actions are not handled if they return a view or any other result type implementing IActionsResult. It is recommend that you use the built-in UseExceptionHandler extension method defined in the Microsoft.AspNetCore.Diagnostics package to handle view exceptions.
Exception handling and logging behaviour can be changed using the WrapResult and DontWrapResult attributes for methods and classes.

除此之外, ABPExceptionFilter還會觸發AbpHandledExceptionData eventbus event.且,經由ABPExceptionFilter處理之後,會將異常信息轉換為ErrorInfo,並以view或Json的形式返回給客戶端。所以當response通過ABPExceptionFilter之後便不再包含Exception了,自然我們的Filter捕捉不到了。

由此,想到兩個解決方法
一 經由Event bus再次將異常拋出(很明顯,如果是為瞭解決本問題的話,邏輯不通,很差的解決方式。已經被catch的異常再拋出來被自定義的filter去處理,七擒孟獲)
但為了熟悉這部分的代碼邏輯還是做了一下實現。

 1 public class MyExceptionHandler : IEventHandler, ITransientDependency
 2 {
 3     public ILogger Logger { get; set; }
 4 
 5     public MyExceptionHandler()
 6     {
 7         Logger = NullLogger.Instance;
 8     }
 9 
10     public void HandleEvent(AbpHandledExceptionData eventData)
11     {
12         Logger.Info(eventData.Exception.ToString());
13         throw eventData.Exception;
14     }
15 }

 

如果是為了別的一些功能,上面利用EventBus來處理的方式也可以借鑒。

二是禁用ABPExceptionFilter改為使用我們自己的filter

禁用ABPExceptionFilter
除上面聲明Filter之外還需要在Configure中app.UseMvc之後添加

// Remove AbpExceptionFilter
var ops = app.ApplicationServices.GetRequiredService<IOptions<MvcOptions>>().Value;
var abpExceptionFilter = ops.Filters.FirstOrDefault(f =>
(f as ServiceFilterAttribute)?.ServiceType == (typeof(AbpExceptionFilter)));
ops.Filters.Remove(abpExceptionFilter);

此方法也有不好的地方,即除我們自定義的異常外,其他異常並不能再由ABPExceptionFilter來處理。

改良最佳版:
我們的最根本的目的其實是更改HttpStatusCode,所以即便Exception被ABPExceptionFilter 封裝成ErrorInfo來說對我們影響並不大,只要能讓我們的自定義Filter catch住異常即可,因此,在Configuresevice中註冊filter時聲明順序即可。

options.Filters.AddService(typeof(myExceptionFilter), order: 1);

 

另:由ABPExceptionFilter介紹可知,它並不會catch住所有類型的異常,如果想對任意類型的異常進行處理,使用middleware可能會更好。

參考內容:

github:
https://github.com/aspnetboilerplate/aspnetboilerplate/issues/1550
https://github.com/aspnetboilerplate/aspnetboilerplate/issues/3280

sessionliang大佬的博客

HK Zhang大佬的博客


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

-Advertisement-
Play Games
更多相關文章
  • 使用System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile進行MD5加密時,會出現已過時 ...
  • 1. IsAssignableFrom實例方法 判斷一個類或者介面是否繼承自另一個指定的類或者介面。 輸出結果: IDog was inherited from IAnimalDog was inherited from IAnimalDog was inherited from IDogCate ...
  • 最近把項目更新到了ASP.Net Core 2.2,發佈之後發現在IIS下使用SQLite資料庫不行了,報異常說不能打開資料庫。"unable to open database file",奇了個怪了。照理說這個不是許可權就是路徑錯了,許可權直接加了Everyone也無濟於事,後來換成絕對路徑就可以了,... ...
  • 開發人員之所以花費大量時間來重點設計控制器和模型對象,是因為在這些領域中,精心編寫的整潔代碼是開發一個可維護Web應用程式的基礎。 3.1 視圖的作用 視圖的職責是向用戶提供用戶界面。當控制器針對被請求的URL執行完合適的邏輯後,就將要顯示的內容委托給視圖。 不像基於文件的Web框架,比如ASP.N ...
  • 索引: 目錄索引 一.API 列表 .ListAsync() .ListAsync<M>() 如: .ListAsync<AgentInventoryRecord>() , 用於 單表/多表連接 查詢. .ListAsync<VM>() 如: .ListAsync<AgentVM>() , 用於 單 ...
  • OpenCvSharp是封裝了OpenCV的.net版本 項目地址:https://github.com/shimat/opencvsharp 簡單使用: 1、NuGet安裝 2、使用OpenCvSharp打開一張圖片,需要添加 OpenCvSharp 命名空間 運行結果: ...
  • 實際開發中我們需要對一些公共類庫進行開發,並基於Jenkins進行CI/CD(CI:持續集成,CD:持續部署),其他項目通過NuGet引用。 "上文" 講述瞭如何搭建本地NuGet伺服器併發布NuGet包,這裡不再贅述。 CI/CD流程如下圖: 首先公共類庫代碼通過Git管理,編輯完代碼後上傳到Gi ...
  • 1、 Ver是頁面定義的變數 2、 asp.net 頁面定義為 <link href="/company/them/page.css?v=<%=Ver%>" rel="stylesheet" type="text/css" /> 輸出結果為 <link href="them/page.css?v=& ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...