需求:
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容器
不要使用全局配置与标签一起使用 会造成多次调用
在这里推荐使用过滤器而不是中间件,
贴上一张大佬的过滤器调用图
结果:
|