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.输入一个不存在的请求:
本文来自博客园,作者:HuTiger,转载请注明原文链接:https://www.cnblogs.com/huguodong/p/12757344.html,欢迎加入qq群927460240学习讨论