asp.net core 统一模型验证拦截实现

在使用webapi对外提供服务的时候,我们希望提供一个统一的返回值例如 {“code”:1,”message”:”ok”,”data”:””}。为了解耦会对未处理的异常和模型验证进行统一处理。本文介绍了asp.net core 3.1版本中实现统一模型验证的实现方法。

在asp.net core中的过滤器和framework中的过滤器使用上并没有太大差异。新建过滤器ModelVerificationFilter.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class ModelVerificationFilter : IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context)
{
}

public void OnActionExecuting(ActionExecutingContext context)
{
if (context.ModelState.IsValid)
{
return;
}

var errorMessage = context.ModelState
?.FirstOrDefault(m => m.Value.ValidationState == ModelValidationState.Invalid).Value
?.Errors
?.FirstOrDefault()
?.ErrorMessage;

context.HttpContext.Response.StatusCode = (int) HttpStatusCode.BadRequest;
context.Result = new ObjectResult(new ResponseVm(errorMessage, 400));
}
}

这里在发现模型验证失败的时候,返回第一个模型验证错误信息,并把http的状态码设置为BadRequest。代码中ResponseVm类是前面提到的统一返回值类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class ResponseVm
{
public ResponseVm(string message, int code)
{
Message = message;
Code = code;
}

public ResponseVm()
{
Message = "ok";
Code = 0;
}

/// <summary>
/// 错误信息
/// </summary>
public string Message { get; set; }

/// <summary>
/// 错误码
/// </summary>
public int Code { get; set; }

public static ResponseVm Success(string msg = "ok")
{
return new ResponseVm(msg, 0);
}

public static ResponseVm Failed(string msg = "error", int code = -1)
{
return new ResponseVm(msg, code);
}
}

设置好过滤器之后发现并没有输出我们要求的结果,而是产生了一个系统默认的模型验证错误的返回值。其中Source是我们要验证的字段。

1
2
3
4
5
6
7
8
9
10
11
12
{
"errors": {
"Source": [
"来源 必须在 1 至 2 之间"
]
...
},
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "|61e0ca29-42ac2f842289c956."
}

参考官方文档Web API应用-概述-自动 HTTP 400响应一节。

使用 2.1 的兼容性版本时,HTTP 400 响应的默认响应类型为 SerializableError。 下述请求正文是序列化类型的示例:
使用 2.2 或更高版本的兼容性版本时,HTTP 400 响应的默认响应类型为 ValidationProblemDetails。
若要禁用自动 400 行为,请将 SuppressModelStateInvalidFilter 属性设置为 true。 将以下突出显示的代码添加到 Startup.ConfigureServices:

1
2
3
4
5
6
7
services.AddControllers()
.ConfigureApiBehaviorOptions(options =>
{
...
options.SuppressModelStateInvalidFilter = true;
...
});

按文档修改后,统一模型验证拦截成功。两种方法配置

1
2
3
4
services.Configure<ApiBehaviorOptions>(o =>
{
o.SuppressModelStateInvalidFilter = true;
});
1
2
services.AddControllers()
.ConfigureApiBehaviorOptions(opt => opt.SuppressModelStateInvalidFilter = true)

参考:

  1. https://docs.microsoft.com/zh-cn/aspnet/core/web-api/?view=aspnetcore-3.1#automatic-http-400-responses