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;
        }
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM