前言
在实际应用场景中我们常常要对接口的入参进行校验, 例如分页大小是否正确, 必填参数是否已经填写等等.
最简单的实现方式如下图, 这种在实际开发中代码过于冗余, 而且不灵活. 今天介绍一种统一参数校验的方式: System.ComponentModel.Annotations
教程
一. 使用nuget安装 System.ComponentModel.Annotations
二. 在请求参数上加属性
头部引用
using System.ComponentModel.DataAnnotations;
原生的组件上就提供了丰富的参数校验规则, 也支持自定义规则.
- Required 必填, 示例:[Required(ErrorMessage = "ID是必填项")] 需要注意除了string类型的其他的值类型由于会赋予默认值, 所以加这个属性的时候值类型字段需要设置为可为空 例如 int? Id {get;set;}
- Range 范围校验, 示例 [Range(1,99999999,ErrorMessage ="请输入正确的页码")]
- Compare 比较 与指定的字段值进行比较 [Compare("MyOtherProperty")]两个属性必须相同值,比如我们要求用户重复输入两次邮件地址时有用
- CreditCard 信用卡号
- EmailAddress 是否为邮件
- EnumDataType 校验枚举类型 示例: [EnumDataType(typeof(EnumModels.ResponseHttpCode),ErrorMessage = "未知的类型")]
- MaxLength 最大长度, 示例: [MaxLength(50,ErrorMessage = "昵称不能超过50个字")]
- MinLength 最小长度 , 示例: [MinLength(2,ErrorMessage = "昵称不能少于2个字")]
- StringLength 字符串长度不能超过给定的最大长度,也可以指定最小长度. 示例: [StringLength(50, ErrorMessage = "昵称只能介于2-50个字", MinimumLength = 2)]
- Url url格式, 示例: [Url(ErrorMessage = "链接格式错误")]
- RegularExpression 正则表达式 示例: [RegularExpression(@"^[1]{1}[3,4,5,6,7,8,9]{1}\d{9}$", ErrorMessage = "手机号码格式错误")]
三. 接口使用
请求参数
public class IdHeader { /// <summary> /// Id /// </summary> [Required(ErrorMessage = "请填写id")] public string Id { get; set; } }
接口
public IActionResult TestCode([FromBody]IdHeader req) { return Ok(new { req.Id }); }
在.net core 3.1中 我们请求时给id不负值, 将返回以下结果
{ "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1", "title": "One or more validation errors occurred.", "status": 400, "traceId": "|ae306434-48bb5a7d72259168.", "errors": { "Id": [ "请填写id" ] } }
一般情况我们需要返回自己定义的格式, 所以我们需要先关闭自动校验, .net core 2.x和 .net framework默认是不自动校验的, 无需关闭
在Startup.cs里的ConfigureServices 添加如下代码关闭自动校验
//关闭参数自动校验,我们需要返回自定义的格式 services.Configure<ApiBehaviorOptions>((o) => { o.SuppressModelStateInvalidFilter = true; });
然后我们需要添加 OnActionExecuting 过滤器
添加过滤器
public class ActionFilter : IActionFilter { /// <summary> /// action执行前 /// </summary> /// <param name="context"></param> public void OnActionExecuting(ActionExecutingContext context) { //校验参数 if (!context.ModelState.IsValid) { var errorMsg = context.ModelState.Values.SelectMany(e => e.Errors).Select(e => e.ErrorMessage).FirstOrDefault(); context.Result = new OkObjectResult(new { Code = 702, Msg = string.IsNullOrWhiteSpace(errorMsg) ? "参数校验错误" : errorMsg, Data = new {} }); return; } } /// <summary> /// action执行后 /// </summary> /// <param name="context"></param> public void OnActionExecuted(ActionExecutedContext context) { } }
.net core 使用过滤器, 在Startup.cs里的ConfigureServices 添加如下代码使用过滤器
services.AddMvc(o => { //action 过滤器 o.Filters.Add<ActionFilter>(); })
.net webapi 使用过滤器, 在 webapiConfig.cs 里的 Register 里添加代码
config.Filters.Add(new App_Start.ActionFilter());//action过滤器
最后的结果
{ "code": 702, "msg": "请填写id", "data": {} }
这样我们就可以自定义我们返回参数
四. 自定义参数校验
虽然官方已经提供了不少验证方法, 但是可能还不够我们使用, 例如身份证号, 行政区划代码等等.
电话号码官方已经提供了一个,但是不适用于我们中国, 我们以校验中国手机号码为例, 来讲自定义参数校验
主要方法是: 自定义类 , 继承 ValidationAttribute, 然后复写 IsValid
/// <summary> /// 是否为中国手机号码 /// </summary> public class ChinaMobilPhoneAttribute : ValidationAttribute { /// <summary> /// 复写 /// </summary> /// <param name="value"></param> /// <returns></returns> public override bool IsValid(object value) { if (!(value is string)) return false; var val = (string)value; return Regex.IsMatch(val, @"^[1]{1}[3,4,5,6,7,8,9]{1}\d{9}$"); } }
然后入参校验
/// <summary> /// Id 具体值请参考具体接口 /// </summary> [ChinaMobilPhone(ErrorMessage = "请填写正确的手机号")] public string PhoneNumber { get; set; }
测试
错误结果
正确结果
通过以上方式我们轻松实现各种参数校验
C# .net framework .net core 3.1 请求参数校验, DataAnnotations, 自定义参数校验