webapi框架搭建系列博客
前言
上一篇我們已經完成了項目的日志管理,在項目開發中日志會經常記錄程序中的異常,供后續問題排查使用。本篇講如何在webapi里加入異常處理機制。
目的和原則
1、程序任何地方都不能catch掉異常,如果要catch也請重新throw異常或是將異常記錄到日志里。避免異常被“吃掉“,導致無法排查程序的bug。
2、webapi接口的”請求成功“和”請求失敗“以一定的標准規范提供給外部
我的規范為:
所有的成功請求返回200(response的status為200),返回的結果以json封裝
所有的失敗請求返回非200,錯誤以json返回,錯誤的內容為Message的值,如{"Message":"這里是異常的內容描述"}
3、如果為已知異常(即我們代碼里寫的throw異常)可簡單的記錄到日志,但如果是未知異常(我們不知道是哪里拋出的異常,往往也是程序的bug)則記錄到特殊的日志文件里,如上篇的log/error目錄下。
參考
微軟webapi異常處理:https://docs.microsoft.com/zh-cn/aspnet/web-api/overview/error-handling/
步驟如下
自定義異常類
此異常類即是”已知“異常,約定程序里我們自己拋出的異常都用此類,Message屬性記錄異常的描述信息
using System;
using System.Runtime.Serialization;
namespace webapi.Exceptions
{
public class KnownException : Exception
{
public KnownException():base()
{
}
public KnownException(string message) : base(message)
{
}
public KnownException(string message, Exception innerException) : base(message, innerException)
{
}
protected KnownException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
}
}
創建webapi異常過濾器
創建WebApiExceptionFilterAttribute類,代碼如下
using System.Net;
using System.Net.Http;
using System.Web.Http.Filters;
using log4net;
namespace webapi.Exceptions
{
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());
if (exception is KnownException)
{
log.Debug(logMessage);
}
else
{
log.Error(logMessage, exception);
}
actionExecutedContext.Response = actionExecutedContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, exceptionMessage);
}
}
}
在webapi里使用異常過濾最簡單的方法就是繼承自ExceptionFilterAttribute類,並重寫OnException方法並寫入自己的異常處理邏輯
將異常過濾器加到webapi里
修改之前的WebApiConfig.OwinWebApiConfiguration方法,代碼如下
/// <summary>
/// 返回webapi的httpconfiguration配置
/// 用於webapi應用於owin技術時使用
/// </summary>
/// <returns></returns>
public static HttpConfiguration OwinWebApiConfiguration(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();//開啟屬性路由
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Filters.Add(new WebApiExceptionFilterAttribute());
return config;
}
增加的只是config.Filters.Add(new WebApiExceptionFilterAttribute());這一句
測試結果
創建用於測試的控制器,寫兩個接口分別模擬程序bug拋出的未知異常和自己拋出的已知異常
using System;
using System.Web.Http;
using webapi.Exceptions;
namespace webapi.example
{
[RoutePrefix("api/exceptionTest")]
public class ExceptionTestController : ApiController
{
/// <summary>
/// 模擬程序bug拋出的異常
/// </summary>
/// <returns></returns>
[Route("unknown"),HttpGet]
public IHttpActionResult UnKnow()
{
throw new Exception("未知的異常");
}
/// <summary>
/// 模擬主動拋出的業務異常
/// </summary>
/// <returns></returns>
[Route("known"), HttpGet]
public IHttpActionResult Know()
{
throw new KnownException("已知的異常");
}
}
}
返問兩個接口會得到內容為{"Message":"xxx"},status為400的respose,和我們的約定規則一樣。
