Asp.net Core 异常日志与API返回值处理

需求:

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容器

不要使用全局配置与标签一起使用 会造成多次调用

 

在这里推荐使用过滤器而不是中间件,

 

贴上一张大佬的过滤器调用图

 

 

结果:

 

posted @ 2019-01-03 15:57  AnAng  阅读(1695)  评论(11编辑  收藏  举报