参数模型验证 ⼀般是对传⼊的参数按照制定规则校验,该章节主要演⽰在服务端对传⼊参数进⾏校验校验主要包括3点:1,定义验证规则2,按照规则进⾏检查3,错误报告
1,定义验证规则
这⾥介绍3中验证⽅式:
⽅式⼀:使⽤ Data Annotations程序集,通过属性注解⽅式,例如 [Required]、[MaxLength] 等⽅式⼆:⾃定义属性 Attribute 验证
⽅式三:使⽤ FluentValidation ⽅式验证 (推荐)
⽅式⼀ 和 ⽅式⼆ 都要引⼊下边的程序集:
引⼊程序集:System.ComponentModel.Annotations 项⽬没有的需要安装⼀下该程序包
⽅式⼀:属性注解验证
优点:简单
缺点:只能作⽤在属性上、存在代码侵⼊、校验⽅式简单、验证只能在Controller的Action中使⽤,不⽀持⾮Controller中或者控制台程序的验证
1 public class ProductsDto 2 {
3 [Display(Name = \"商品编号\")]
4 [Required(ErrorMessage = \"{0}是必填项\")]
5 [StringLength(maximumLength: 10, MinimumLength = 5, ErrorMessage = \"{0}的长度范围是{2}到{1}\")] 6 public string ProductCode { get; set; } 7
8 [Display(Name = \"商品名称\")]
9 [Required(ErrorMessage = \"{0}是必填项\")]
10 [MinLength(1, ErrorMessage = \"{0}的最⼩长度是1\")]11 public string ProductName { get; set; }12
13 [Display(Name = \"商品价格\")]
14 [Required(ErrorMessage = \"{0}是必填项\")]
15 [RegularExpression(@\"^(?!.{12,}$)\\d{1,18}(\\.\\d{1,2})?$\格式不规范,{0}要保留⼩数点后1到2位\")]16 public decimal? Price { get; set; }17
18 [Display(Name = \"会员价\")]
19 [Compare(\"Price\必须和{1}相同\")]20 public decimal? VipPrice { get; set; }21
22 [Display(Name = \"状态\")]
23 [Range(0, 1, ErrorMessage = \"{0}必须是{1}或{2}\")]24 public int? Status { get; set; }2526 }
C#简单解释: Display 定义别名Required 必填项
StringLength 字符串长度验证 maximumLength: 10 最⼤长度 MinimumLength = 5 最⼩长度
ErrorMessage = \"{0}的长度范围是{2}到{1}\" -- 错误提⽰内容
{0}、{1}、{2} 是占位符,{0}表⽰当前属性 ,{1}第⼀个参数 maximumLength , {2}是第⼆个参数MinimumLength RegularExpression 定义正则表达式Compare 和其他属性进⾏⽐较
通过接⼝进⾏测试,返回错误报告如下:AddProducts(ProductsDto products)
⽅式⼆:⾃定义属性 Attribute 验证
优点:可以将验证声明到类级别上、在⽅式⼀的基础上进⼀步封装、可以进⾏复杂的规则校验
缺点:依然存在代码侵⼊(⼩到可以忽略不计),验证只能在Controller的Action中使⽤,不⽀持⾮Controller中或者控制台程序的验证定义⼀个类:LoginFilterValidationAttribute,继承 ValidationAttribute 属性,重写IsValid()⽅法
public class LoginFilterValidationAttribute : ValidationAttribute {
protected override ValidationResult IsValid(object value, ValidationContext validationContext) {
var userDto = (UsersDto)validationContext.ObjectInstance; //获取类的实例对象 //验证⽤户名不能为空
if (string.IsNullOrWhiteSpace(userDto.Username)) {
return new ValidationResult(\"⽤户名不能为空\ }
//验证密码不能为空
if (string.IsNullOrWhiteSpace(userDto.Password)) {
return new ValidationResult(\"密码不能为空\ }
//验证⼿机号不能为空
if (string.IsNullOrWhiteSpace(userDto.Mobile)) {
return new ValidationResult(\"⼿机号不能为空\ }
//⼿机号输⼊规则验证
if (!string.IsNullOrWhiteSpace(userDto.Mobile)) {
var regex = new Regex(@\"^1[3456789]\\d{9}$\"); if (!regex.IsMatch(userDto.Mobile))
returnnewValidationResult(\"⼿机号不符合规则\验证密码强度if(!string.IsNullOrWhiteSpace(userDto.Password)){//正则var regex=newRegex(@\" (?=.*[0-9]) #必须包含数字
(?=.*[a-zA-Z]) #必须包含⼩写或⼤写字母 (?=([\\x21-\\x7e]+)[^a-zA-Z0-9]) #必须包含特殊符号 .{6,16} #⾄少6个字符,最多16个字符
\是否匹配,如果不匹配则返回if(!regex.IsMatch(userDto.Password)){returnnewValidationResult(\"密码不符合规则,请重新输⼊\
C#
在Model类中直接如下声明即可:
[LoginFilterValidation] //将参数验证声明到类上public class UsersDto{
public int Userid { get; set; }
public string Username { get; set; } 。。。}
C#
通过接⼝测试,返回错误内容如下:AddUsers(UsersDto users)
⽅式三:使⽤ FluentValidation ⽅式验证 (推荐)
优点:⽀持任何场景下的模型验证(Controller层和Service层都能⽤),且不侵⼊代码,⽀持复制规则验证,规则定义类似⽅式⼆缺点:适合⼤型项⽬(个⼈感觉),⼩项⽬⽤上边两种⽅式够⽤了使⽤该⽅式需要引⼊下边程序包:FluentValidation.AspNetCore
创建⾃定义类:RegisterValidationAttribute 、继承 AbstractValidator 1 public class RegisterValidationAttribute : AbstractValidator 3 public RegisterValidationAttribute() 4 { 5 //如果设置为Stop,则检测到失败的验证,则⽴即终⽌,不会继续执⾏剩余属性的验证。 6 //默认值为 Continue 7 CascadeMode = CascadeMode.Stop; 8 9 RuleFor(x => x.Username).NotEmpty().WithMessage(\"⽤户名不能为空\") 10 .Length(2, 12).WithMessage(\"⽤户名⾄少2个字符,最多12个字符\");11 12 RuleFor(x => x.Password).NotEmpty().WithMessage(\"密码不能为空\") 13 .Length(6, 16).WithMessage(\"密码长度⾄少6个字符,最多16个字符\") 14 .Must(EncryptionPassword).WithMessage(\"密码不符合规则,必须包含数字、⼩写或⼤写字母、特殊符号\");15 16 RuleFor(x => x.ConfirmPassword).NotEmpty().WithMessage(\"确认密码不能为空\")17 .Must(ComparePassword).WithMessage(\"确认密码必须跟密码⼀样\");18 19 RuleFor(x => x.Mobile).NotEmpty().WithMessage(\"⼿机号不能为空\")20 .Must(IsMobile).WithMessage(\"⼿机号格式不正确\");21 }22 23 /// 26 /// 27 private bool EncryptionPassword(string password)28 { 29 //正则 30 var regex = new Regex(@\" 31 (?=.*[0-9]) #必须包含数字 32 (?=.*[a-zA-Z]) #必须包含⼩写或⼤写字母33 (?=([\\x21-\\x7e]+)[^a-zA-Z0-9]) #必须包含特殊符号34 .{6,16} #⾄少6个字符,最多16个字符 35 \⽐较两次密码是否⼀样41/// 42/// 这⾥传的是:C C# 使⽤⽅式很简单,如下: 1 [HttpPost] 2 public async Task 4 var result = new CommonResult(); 5 6 //使⽤如下两⾏代码即可 7 RegisterValidationAttribute validationRules = new RegisterValidationAttribute(); 8 ValidationResult validaResult = validationRules.Validate(usersDto); 9 10 if (validaResult.IsValid) //校验通过11 { 12 //执⾏正常的业务逻辑13 result.ResultCode = 1;14 result.ResultMsg = \"成功\";15 } 16 else //验证没通过,返回错误信息17 { 18 result.ResultCode = 0; 19 result.ResultMsg = validaResult.ToString(\"||\");20 } 21 return Ok(result);22 } C# 测试结果,分别返回如下错误提⽰: 如果将 Stop 替换成 Continue 会发⽣什么? 1 CascadeMode = CascadeMode.Stop;2 替换成: 3 CascadeMode = CascadeMode.Continue; C# 测试结果如下:错误信息会全部返回 1 { 2 \"resultCode\": 0, 3 \"resultMsg\": \"'⽤户名' 不能为空。||⽤户名⾄少2个字符,最多12个字符||'密码' 不能为空。||密码长度⾄少6个字符,最多16个字符||密码不符合规则,必须包含数字、⼩写或⼤写字母、特殊符号||'验证码' 不能为空。||请输⼊4位验证码\"4 } C# 如果你嫌每次都要实例化⼀次对象进⾏注册,你也可以使⽤全局注册,直接在 Staup 中注册即可 1 services.AddControllers() 2 //记得引⼊ using FluentValidation.AspNetCore 3 .AddFluentValidation(option => 4 { 5 //所有验证类继承该接⼝,使⽤接⼝标识 IModelValidator 批量注册 6 //option.RegisterValidatorsFromAssemblyContaining 8 //单个类注册 9 option.RegisterValidatorsFromAssemblyContaining C#参考⽂档: 因篇幅问题不能全部显示,请点此查看更多更全内容