需求:
1、對異常進行捕獲記錄日志 並且修改返回值給前端
解釋:
ILogger4是自定義的一個日志,更改它就好
解決方案1:
使用中間件進行異常捕獲並且修改其返回值
public class ErrorMiddleware { private readonly RequestDelegate _next; ILogger4<ErrorMiddleware> logger4; public ErrorMiddleware(RequestDelegate next,ILogger4<ErrorMiddleware> logger4) { _next = next; this.logger4 = logger4; } public async Task Invoke(HttpContext httpContext) { try { await _next(httpContext); } catch (Exception e) { logger4.LogError(e,e.Message+"\r\n"+e.StackTrace); throw e; } } }
這一步簡單,從源碼里 ExceptionHandlerMiddleware.cs類里 Copy的代碼
使用中間件進行修改返回值
public class ResultMiddleware { private readonly RequestDelegate _next; public ResultMiddleware(RequestDelegate next) { _next = next; } public async Task Invoke(HttpContext httpContext) { await _next(httpContext);
string bodyString = "<p>不好意思 系統正在升級維護 請稍后再試</p>";
var by = Encoding.UTF8.GetBytes(bodyString);
var heard =(Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpResponseHeaders)httpContext.Response.Headers; heard.HeaderContentLength = by.Length.ToString();
//必須要手動設置請求頭的ContentLength大小 才能修改返回值的數據 await httpContext.Response.Body.WriteAsync(by);
}
}
這是從網上copy 修改的代碼,不推薦使用 開銷太大 轉為過濾器
解決方案2:
使用中間件進行異常捕獲並且修改其返回值
異常過濾器
/// <summary> /// 異常過濾器 /// </summary> public class ErrorFilter :Attribute,IExceptionFilter { ILogger4<ErrorFilter> logger4; /// <summary> /// 標簽 /// </summary> public ErrorFilter() { } /// <summary> /// 全局配置 /// </summary> /// <param name="logger4"></param> public ErrorFilter(ILogger4<ErrorFilter> logger4) { this.logger4 = logger4; } public void OnException(ExceptionContext context) { var e = context.Exception; logger4.LogError(e, e.Message + "\r\n" + e.StackTrace); context.Result = new JsonResult(new BaseResult(e.Message)); } }
方法過濾器
/// <summary> /// 對打上該標記的 返回結果為JsonResult的請求進行Result包裝 /// </summary> public class ApiResultFilter : Attribute, IActionFilter { /// <summary> /// 執行方法體之后 /// </summary> /// <param name="context"></param> public void OnActionExecuted(ActionExecutedContext context) { var result = context.Result; if (result!=null &&result is JsonResult resulta) { context.Result = new JsonResult(new BaseResult(resulta.Value)); } } /// <summary> /// 執行方法體之前 /// </summary> /// <param name="context"></param> public void OnActionExecuting(ActionExecutingContext context) { //不做修改 } }
可以使用標簽的方法
/// <summary> /// 測試 返回過濾器 /// </summary> /// <returns></returns> [ErrorFilter] [ApiResultFilter] [HttpGet] public IActionResult TestReuslt() { throw new Exception("AA"); var obj = new { A = "321" }; return Json(obj); }
也可以使用全局配置的方法
//注冊過濾器 services.AddSingleton<ApiResultFilter>(); services.AddSingleton<ErrorFilter>(); services.AddMvc( config => { config.Filters.AddService(typeof(ApiResultFilter)); config.Filters.AddService(typeof(ErrorFilter)); }) .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
注意:
打上的標簽無法獲取IOC容器
不要使用全局配置與標簽一起使用 會造成多次調用
在這里推薦使用過濾器而不是中間件,
貼上一張大佬的過濾器調用圖
結果: