ASP.NET WebApi項目框架搭建(五):異常處理


一、前言

目的和原則

  1、程序任何地方都不能catch掉異常,如果要catch也請重新throw異常或是將異常記錄到日志里。避免異常被“吃掉“,導致無法排查程序的bug。

  2、webapi接口的”請求成功“和”請求失敗“以一定的標准規范提供給外部

  3、如果為已知異常(即我們代碼里寫的throw異常)可簡單的記錄到日志,但如果是未知異常(我們不知道是哪里拋出的異常,往往也是程序的bug)則記錄到特殊的日志文件里,如上篇的log/error目錄下。

二、新建公共方法類庫

1.新建一個類庫用來存儲公共方法以供項目或者其他庫調用。

 2.安裝Newtonsoft

 3.新建Utils類,寫一個返回Json的類

public class Utils
    {
        public static HttpResponseMessage toJson(dynamic code,object result)
        {
            var response = Newtonsoft.Json.JsonConvert.SerializeObject(result);
            HttpResponseMessage res = new HttpResponseMessage(code);
            res.Content = new StringContent(response, Encoding.UTF8, "application/json");
            return res;
        }
    }

4.系統的HttpStatusCode枚舉可能不能滿足我們的需求,所以新建枚舉類HttpCode,定義我們的返回碼:

   public enum HttpCode
    {
        /// <summary>
        /// 成功
        /// </summary>
        SUCCESS = 200,
        /// <summary>
        /// 失敗
        /// </summary>
        ERROR = 500,

        /// <summary>
        /// 參數錯誤
        /// </summary>
        ERROR_PARAM = 600,
        /// <summary>
        /// 參數為空
        /// </summary>
        NULL_PARAM = 601,

        /// <summary>
        /// 數據庫異常
        /// </summary>
        DB_ERROR = 600,

        /// <summary>
        /// 數據操作成功
        /// </summary>
        OK = 1,

        /// <summary>
        /// 數據操作成功
        /// </summary>
        FAILED = 0,


    }

4.引用公共類庫

二、定義異常

1.新建Exceptions文件夾,新建KnownException類,繼承Exception,這個類主要是拋出已知的異常信息

public class KnownException : Exception
    {
        public HttpCode code;
        public string msg;

        public KnownException(HttpCode code, string msg)
        {
            this.code = code;
            this.msg = msg;
        }
    }

2.項目Models文件夾下創建一個Result類,用來定義消息返回格式,對於 null添加注解 [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] 數據可以選擇忽略,不返回給客戶端

public class Result
    {
        /// <summary>
        /// 碼值
        /// </summary>
        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
        public HttpCode code;
        /// <summary>
        /// 信息
        /// </summary>
        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
        public string msg;
        /// <summary>
        /// 具體的數據
        /// </summary>
        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
        public object data;

        public Result()
        {

        }
        public Result(HttpCode code, string msg, object data)
        {
            this.code = code;
            this.msg = msg;
            this.data = data;
        }
    }

3.Exceptions文件夾下新建WebApiExceptionFilterAttribute.cs,繼承ExceptionFilterAttribute,重寫OnException方法

/// <summary>
    /// 異常處理
    /// </summary>
    public class WebApiExceptionFilterAttribute : ExceptionFilterAttribute
    {
       
        public override void OnException(HttpActionExecutedContext actionExecutedContext)
        {
            var exception = actionExecutedContext.Exception;//獲取產生的異常對象
            var exceptionMessage = exception.Message;
            var logMessage =
                $@"controller.action={actionExecutedContext.ActionContext.ControllerContext.ControllerDescriptor.ControllerName}.{actionExecutedContext.ActionContext.ActionDescriptor.ActionName}:exception="
                + exception.Message;//異常內容
            ILog log = LogManager.GetLogger(actionExecutedContext.ActionContext.ControllerContext.Controller.GetType());
            Result result = new Result();
            if (exception is KnownException)//如果是已知異常
            {
                log.Debug(logMessage);
                var ex = (KnownException)actionExecutedContext.Exception;
                result.code = ex.code;
                result.msg = ex.msg;
            }
            else//如果是未知異常
            {
                log.Error(logMessage, exception);
                result.code = HttpCode.ERROR;
                result.msg = "內部錯誤";
                result.data = exceptionMessage;
            }
            actionExecutedContext.ActionContext.Response = Utils.toJson(HttpStatusCode.BadRequest, result);

        }
    }

4.將異常過濾器加到webapiconfig.cs里

config.Filters.Add(new WebApiExceptionFilterAttribute());

5.控制器新建一個請求,分別模擬拋出已知異常和未知異常:

        [Route("know")]
        [HttpGet]
        public IHttpActionResult Know()
        {
            throw new KnownException(HttpCode.DB_ERROR,"數據庫異常了");

        }
        [HttpGet]
        [Route("unknow")]
        public IHttpActionResult UnKnow()
        {
            throw new System.IO.IOException();
        }

6.測試結果:

 

 

7.異常結果也輸出到了日志:

 

 

二、消息異常處理

當我們輸入一個不存在的請求的時候,會提示控制器不存在的信息,如果我們想自定義消息返回格式,可以通過DelegatingHandler去重寫異常信息。

1.Expections文件夾新建CustomErrorMessageDelegatingHandler.cs繼承DelegatingHandler

public class CustomErrorMessageDelegatingHandler : DelegatingHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            return base.SendAsync(request, cancellationToken).ContinueWith(ResponseMessage);
        }
        public HttpResponseMessage ResponseMessage(Task<HttpResponseMessage> request)
        {
            HttpResponseMessage response = request.Result;
            HttpError error = null;

            if (response.TryGetContentValue<HttpError>(out error))
            {
                //添加自定義錯誤處理
                //error.Message = "Your Customized Error Message";
            }
            if (error != null)
            {
                ////獲取拋出自定義異常,有攔截器統一解析
                return Utils.toJson(response.StatusCode, new { code = response.StatusCode, message = error.Message }); 
            }
            else
            {
                return response;
            }

        }
    }

2.webapiconfig.cs注冊

onfig.MessageHandlers.Add(new CustomErrorMessageDelegatingHandler());

3.輸入一個不存在的請求:

 


免責聲明!

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



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