1. 程式人生 > WINDOWS開發 >ASP.NET WebApi專案框架搭建(五):異常處理

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> DB_ERROR= 600,}

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.異常結果也輸出到了日誌:

技術分享圖片

技術分享圖片