我们开发接口时,一般都会涉及到参数校验、异常处理、封装结果返回等处理。如果每个后端开发在参数校验、异常处理等都是各写各的,没有统一处理的话,代码就不优雅,也不容易维护。所以,我们需要统一校验参数,统一异常处理、统一结果返回,让代码更加规范、可读性更强、更容易维护。
统一参数校验
比如我们需要入参为必填,只需要在实体类字段添加 [Required]
/// <summary>////// </summary>public class AdminInputDto{/// <summary>/// 账号/// </summary>[Required]public string UserName { get; set; }/// <summary>/// 密码/// </summary>[Required]public string Password { get; set; }}
然后再OnActionExecuting 进行验证
public override void OnActionExecuting(ActionExecutingContext context){//模型验证if (!context.ModelState.IsValid){throw new CustomException(context.ModelState.Values.First(p => p.Errors.Count > 0).Errors[0].ErrorMessage, ReturnCode.E1000002);}base.OnActionExecuting(context);}
统一结果返回
统一标准的返回格式。一般一个标准的响应报文对象
code :响应状态码
message :响应结果描述
data:返回的数据
定义一个统一的返回对象模板
/// <summary>/// Service的返回数据/// </summary>public class ReturnData : ReturnData<object>{}/// <summary>/// Service的返回数据/// </summary>public class ReturnData<T>{/// <summary>/// 返回码/// </summary>public ReturnCode Code { get; set; }/// <summary>/// 消息/// </summary>public string Message { get; set; }/// <summary>/// 结果数据/// </summary>public T Data { get; set; }/// <summary>/// 判断处理是否成功/// </summary>public bool Success{get { return ReturnCode.E10000 == Code; }}}
在控制器返回的时候,进行返回包装
/// <summary>/// 处理正常返回的结果对象/// </summary>/// <param name="context"></param>public override void OnActionExecuted(ActionExecutedContext context){if (context.Result != null){var serializerSettings = new JsonSerializerSettings{DateTimeZoneHandling = DateTimeZoneHandling.Local,DateFormatString = "yyyy-MM-ddTHH:mm:ss.fffzz:00",//设置缩进Formatting = Formatting.Indented,//设置json格式为驼峰式ContractResolver = new CamelCasePropertyNamesContractResolver()};var result = context.Result as ObjectResult;JsonResult newresult;if (context.Result is ObjectResult){newresult = new JsonResult(new ReturnData { Message = "操作成功!", Code = ReturnCode.E10000, Data = result.Value }, serializerSettings);}else if (context.Result is EmptyResult){newresult = new JsonResult(new ReturnData { Message = "操作成功!", Code = ReturnCode.E10000 }, serializerSettings);}else{throw new Exception($"未经处理的Result类型:{ context.Result.GetType().Name}");}context.Result = newresult;}base.OnActionExecuted(context);}
统一异常处理
遇到未处理的异常进行统一的封装
/// <summary>/// api异常统一处理过滤器/// </summary>public class ApiExceptionFilterAttribute : ExceptionFilterAttribute{public override void OnException(ExceptionContext context){context.Result = BuildExceptionResult(context.Exception);base.OnException(context);}/// <summary>/// 包装处理异常格式/// </summary>/// <param name="ex"></param>/// <returns></returns>private JsonResult BuildExceptionResult(Exception ex){var returnData = new ReturnData();var exresult = ex as CustomException;var WriteLog = true;if (exresult != null){//异常为自定义的异常returnData.Code = exresult.ErrorCode;returnData.Message = exresult.Message;WriteLog = exresult.WriteLog;}else{//异常为未知异常returnData.Code = ReturnCode.E1000001;returnData.Message = ex.Message;}//TODO 日志var serializerSettings = new JsonSerializerSettings{DateTimeZoneHandling = DateTimeZoneHandling.Local,DateFormatString = "yyyy-MM-ddTHH:mm:ss.fffzz:00",//设置缩进Formatting = Formatting.Indented,//设置json格式为驼峰式ContractResolver = new CamelCasePropertyNamesContractResolver()};return new JsonResult(returnData, serializerSettings);}}
}