Framework
在Framework中,我们一般进行参数验证的时候,以下代码是非常常见的
[HttpPost]
public async Task<JsonResult> SaveNewCustomerAsnyc(AddCustomerInput input)
{
if (!ModelState.IsValid)
{
return Json(Result.FromCode(ResultCode.InvalidParams));
}
}
或者使用IActionFilter进行拦截,如下:
public class ApiValidationFilter : IActionFilter
{
public bool AllowMultiple => false;
public async Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
var method = actionContext.ActionDescriptor.GetMethodInfoOrNull();
if (method == null)
{
return await continuation();
}
if (!actionContext.ModelState.IsValid)
{
var error = actionContext.ModelState.GetValidationSummary();
var result = Result.FromError($"参数验证不通过:{error}", ResultCode.InvalidParams);
return actionContext.Request.CreateResponse(result);
}
return await continuation();
}
}
public static class ModelStateExtensions
{
/// <summary>
/// 获取验证消息提示并格式化提示
/// </summary>
public static string GetValidationSummary(this ModelStateDictionary modelState, string separator = "\r\n")
{
if (modelState.IsValid) return null;
var error = new StringBuilder();
foreach (var item in modelState)
{
var state = item.Value;
var message = state.Errors.FirstOrDefault(p => !string.IsNullOrWhiteSpace(p.ErrorMessage))?.ErrorMessage;
if (string.IsNullOrWhiteSpace(message))
{
message = state.Errors.FirstOrDefault(o => o.Exception != null)?.Exception.Message;
}
if (string.IsNullOrWhiteSpace(message)) continue;
if (error.Length > 0)
{
error.Append(separator);
}
error.Append(message);
}
return error.ToString();
}
}
core
在.net core中用过滤器无法拦截到ModelState,框架会为你自动注册ModelStateInvalidFilter,在自定义的IActionFilter前已执行完成。
基于现有框架的代码编写的话,所以我们不再需要在业务中耦合这样的模型判断代码,系统内部会检查ModelState是否为Valid,如果为InValid会直接返回400 BadRequest,这样就没有必要执行后面的代码,提高效率。因此,操作方法中不再需要以下代码:
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
如果需要控制校验完成后返回自定以的返回体,并记录日志的化,需要在startup的ConfigureServices方法中配置实现:
services.Configure<ApiBehaviorOptions>(options =>
{
options.InvalidModelStateResponseFactory = (context) =>
{
var error = context.ModelState.Values.SelectMany(e => e.Errors).Select(e => e.ErrorMessage).FirstOrDefault();
//记录日志
logger.Error($"参数错误:{error.ToString()}");
//ApieceResponse为自定义的返回类
return new JsonResult(new ApiResponse<string>(CodeConfig.Failed, "参数错误"));
};
});