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.输入一个不存在的请求:

  • 相关阅读:
    在Exchange 2013中重置用户密码
    在exchange邮箱服务器上启用反垃圾邮件功能
    EMC队列 发件人为空 From Address: <>
    zabbix删除历史记录
    ESXi 6.7 CVE-2018-3646警告的处理
    CentOS安装nmap端口查看工具
    webpack学习
    vscode 点滴
    chrome点滴
    前端资料汇总
  • 原文地址:https://www.cnblogs.com/huguodong/p/12757344.html
Copyright © 2011-2022 走看看