zoukankan      html  css  js  c++  java
  • 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.输入一个不存在的请求:

  • 相关阅读:
    2016"百度之星"
    codeforces 55 div2 C.Title 模拟
    codeforces 98 div2 C.History 水题
    codeforces 97 div2 C.Replacement 水题
    codeforces 200 div2 C. Rational Resistance 思路题
    bzoj 2226 LCMSum 欧拉函数
    hdu 1163 九余数定理
    51nod 1225 余数的和 数学
    bzoj 2818 gcd 线性欧拉函数
    Codeforces Round #332 (Div. 2)D. Spongebob and Squares 数学
  • 原文地址:https://www.cnblogs.com/huguodong/p/12757344.html
Copyright © 2011-2022 走看看