Asp.Net Core Web Api 全局异常中间件

中间件处理异常能够获取系统异常

1、添加异常处理中间件AppExceptionHandlerMiddleware

  public class AppExceptionHandlerMiddleware
    {
        private readonly RequestDelegate _next;
        private AppExceptionHandlerOption _option = new AppExceptionHandlerOption();
        private readonly IDictionary<int, string> _exceptionStatusCodeDic;
        private readonly ILogger<AppExceptionHandlerMiddleware> _logger;
        public AppExceptionHandlerMiddleware(RequestDelegate next, Action<AppExceptionHandlerOption> actionOptions, ILogger<AppExceptionHandlerMiddleware> logger)
        {
            _next = next;
            _logger = logger;
            actionOptions(_option);
            _exceptionStatusCodeDic = new Dictionary<int, string>
            {
                { 401, "未授权的请求" },
                { 404, "找不到该页面" },
                { 403, "访问被拒绝" },
                { 500, "服务器发生意外的错误" }
            };
        }

        public async Task Invoke(HttpContext context)
        {
            Exception exception = null;
            try
            {
                await _next(context); //调用管道执行下一个中间件
            }
            catch (AppException ex)
            {
                context.Response.StatusCode = StatusCodes.Status200OK;
                var apiResponse = new ApiResponse(){IsSuccess = false,Message = ex.ErrorMsg};
                var serializerResult = JsonConvert.SerializeObject(apiResponse);
                context.Response.ContentType = "application/json;charset=utf-8";
                await context.Response.WriteAsync(serializerResult);
            }
            catch (Exception ex)
            {
                context.Response.Clear();
                context.Response.StatusCode = StatusCodes.Status500InternalServerError; //发生未捕获的异常,手动设置状态码
                exception = ex;
            }
            finally
            {
                if (_exceptionStatusCodeDic.ContainsKey(context.Response.StatusCode) && !context.Items.ContainsKey("ExceptionHandled")) //预处理标记
                {
                    string errorMsg;
                    if (context.Response.StatusCode == 500 && exception != null)
                    {
                        errorMsg = $"{(exception.InnerException != null ? exception.InnerException.Message : exception.Message)}";
                        _logger.LogError(errorMsg);
                    }
                    else
                    {
                        errorMsg = _exceptionStatusCodeDic[context.Response.StatusCode];
                    }
                    exception = new Exception(errorMsg);
                }
                if (exception != null)
                {
                    var handleType = _option.HandleType;
                    if (handleType == AppExceptionHandleType.Both) //根据Url关键字决定异常处理方式
                    {
                        var requestPath = context.Request.Path;
                        handleType = _option.JsonHandleUrlKeys != null && _option.JsonHandleUrlKeys.Count(
                                         k => requestPath.StartsWithSegments(k, StringComparison.CurrentCultureIgnoreCase)) > 0
                            ? AppExceptionHandleType.JsonHandle
                            : AppExceptionHandleType.PageHandle;
                    }
                    if (handleType == AppExceptionHandleType.JsonHandle)
                        await JsonHandle(context, exception);
                    else
                        await PageHandle(context, exception, _option.ErrorHandingPath);
                }
            }
        }

        /// <summary>
        /// 统一格式响应类
        /// </summary>
        /// <param name="ex"></param>
        /// <returns></returns>
        private ApiResponse GetApiResponse(Exception ex)
        {
            return new ApiResponse() { IsSuccess = false, Message = ex.Message };
        }

        /// <summary>
        /// 处理方式:返回Json格式
        /// </summary>
        /// <param name="context"></param>
        /// <param name="ex"></param>
        /// <returns></returns>
        private async Task JsonHandle(HttpContext context, System.Exception ex)
        {
            var apiResponse = GetApiResponse(ex);
            var serializerResult = JsonConvert.SerializeObject(apiResponse);
            context.Response.ContentType = "application/json;charset=utf-8";
            await context.Response.WriteAsync(serializerResult);
        }

        /// <summary>
        /// 处理方式:跳转网页
        /// </summary>
        /// <param name="context"></param>
        /// <param name="ex"></param>
        /// <param name="path"></param>
        /// <returns></returns>
        private async Task PageHandle(HttpContext context, System.Exception ex, PathString path)
        {
            context.Items.Add("Exception", ex);
            var originPath = context.Request.Path;
            context.Request.Path = path;   //设置请求页面为错误跳转页面
            try
            {
                await _next(context);
            }
            catch
            {

            }
            finally
            {
                context.Request.Path = originPath;   //恢复原始请求页面
            }
        }
    }

2、添加异常处理配置项 AppExceptionHandlerOption

 public class AppExceptionHandlerOption
    {
        public AppExceptionHandlerOption(
            AppExceptionHandleType handleType = AppExceptionHandleType.JsonHandle,
            IList<PathString> jsonHandleUrlKeys = null,
            string errorHandingPath = "")
        {
            HandleType = handleType;
            JsonHandleUrlKeys = jsonHandleUrlKeys;
            ErrorHandingPath = errorHandingPath;
        }

        /// <summary>
        /// 异常处理方式
        /// </summary>
        public AppExceptionHandleType HandleType { get; set; }

        /// <summary>
        /// Json处理方式的Url关键字
        /// <para>仅HandleType=Both时生效</para>
        /// </summary>
        public IList<PathString> JsonHandleUrlKeys { get; set; }

        /// <summary>
        /// 错误跳转页面
        /// </summary>
        public PathString ErrorHandingPath { get; set; }
    }

3、错误处理方案

  /// <summary>
    /// 错误处理方式
    /// </summary>
    public enum AppExceptionHandleType
    {
        JsonHandle = 0,   //Json形式处理
        PageHandle = 1,   //跳转网页处理
        Both = 2          //根据Url关键字自动处理
    }

4、相应结构

 public class ApiResponse
    {
        public int State => IsSuccess ? 1 : 0;
        public bool IsSuccess { get; set; }
        public string Message { get; set; }
    }

5、扩展

  public static class AppExceptionHandlerExtensions
    {
        public static IApplicationBuilder UserAppExceptionHandler(this IApplicationBuilder app, Action<AppExceptionHandlerOption> options)
        {
            return app.UseMiddleware<AppExceptionHandlerMiddleware>(options);
        }

    }

 6、自定义异常类型

 public class AppException:Exception
    {
        public string ErrorMsg { get; set; }
        public AppException(string errorMsg)
        {
            ErrorMsg = errorMsg;
        }
    }

 

posted @ 2019-12-03 15:11  清Q风F  阅读(1079)  评论(0编辑  收藏  举报