Util 应用框架基础(四)- 验证
验证
Util 应用框架对象验证方法
本节介绍 Util 应用框架如何进行验证.
概述
验证是业务健壮性的基础.
.Net 提供了一套称为 DataAnnotations 数据注解的方法,可以对属性进行一些基本验证,比如必填项验证,长度验证等.
Util 应用框架使用标准的数据注解作为基础验证,并对自定义验证进行扩展.
基础用法
引用 Nuget 包
Nuget 包名: Util.Validation.
通常不需要手工引用它.
数据注解
数据注解是一种.Net 特性 Attribute,可以在属性上应用它们.
常用数据注解
下面列出一些常用数据注解,如果还不能满足需求,可以创建自定义的数据注解.
RequiredAttribute 必填项验证
[Required] 验证属性不能是空值.
范例:
public class Test { [Required] public string Name { get; set; } }
[Required] 支持一些参数,可以设置验证失败的提示消息.
public class Test {
[Required(ErrorMessage = "名称不能为空")]
public string Name { get; set; }
}
StringLengthAttribute 字符串长度验证
[StringLength] 可以对字符串长度进行验证.
下面的例子验证 Name 属性的字符串最大长度为 5.
public class Test {
[StringLength(5)]
public string Name { get; set; }
}
还可以同时设置最小长度.
下面验证 Name 属性字符串最小长度为 1,最大长度为 5.
public class Test {
[StringLength(5,MinimumLength = 1)]
public string Name { get; set; }
}
MaxLengthAttribute 字符串最大长度验证
[MaxLength] 也可以用来验证字符串最大长度.
验证 Name 属性的字符串最大长度为 5.
public class Test {
[MaxLength(5)]
public string Name { get; set; }
}
MinLengthAttribute 字符串最小长度验证
[MinLength] 也可以用来验证字符串最小长度.
验证 Name 属性的字符串最小长度为 1.
public class Test {
[MinLength(1)]
public string Name { get; set; }
}
RangeAttribute 数值范围验证
[Range] 用于验证数值范围.
下面验证 Money 属性的值必须在 1 到 5 之间的范围.
public class Test {
[Range( 1, 5 )]
public int Money { get; set; }
}
EmailAddressAttribute 电子邮件验证
[EmailAddress] 用于验证电子邮件的格式.
public class Test {
[EmailAddress]
public int Email { get; set; }
}
PhoneAttribute 手机号验证
[Phone] 用于验证手机号的格式.
public class Test {
[Phone]
public int Tel { get; set; }
}
IdCardAttribute 身份证验证
[IdCard] 用于验证身份证的格式.
它是一个 Util 应用框架自定义的数据注解.
public class Test {
[IdCard]
public int IdCard { get; set; }
}
UrlAttribute Url 验证
[Url] 用于验证网址格式.
public class Test {
[Url]
public int Url { get; set; }
}
RegularExpressionAttribute 正则表达式验证
[RegularExpression] 可以使用正则表达式进行验证.
由于正则表达式比较复杂,对于经常使用的场景,应封装成自定义数据注解.
下面使用正则表达式验证身份证,可以封装到 [IdCard] 数据注解,从而避免正则表达式的复杂性.
public class Test {
[RegularExpression( @"(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)" )]
public string IdCard { get; set; }
}
验证数据注解
虽然在对象属性上添加了数据注解,但它们并不会自动触发验证.
你可以使用 Asp.Net Core 提供的方法验证对象上的数据注解.
Util 提供了一个辅助方法 Util.Validation.DataAnnotationValidation.Validate 用来验证数据注解.
DataAnnotationValidation.Validate 方法接收一个对象参数,只需将要验证的对象实例传入即可.
返回类型为验证结果集合,包含所有验证失败的消息.
大部分情况下,你并不需要调用 DataAnnotationValidation.Validate 方法验证数据注解.
实体,值对象,DTO 等对象已经内置了 Validate 方法,它们会自动验证数据注解.
Util Angular UI 数据注解验证支持
Util Angular UI 支持 Razor TagHelper 服务端标签语法.
可以在表单组件使用 Lambda 表达式绑定 DTO 对象属性.
TestDto 参数对象 Name 属性使用 [Required] 设置必填项验证.
Razor 页面声明 TestDto 模型, 定义输入框 util-input,使用 for 属性绑定到 TestDto 参数对象的 Name 属性.
Razor 页面最终会生成 html,表单标签 nz-form-label 添加了 nzRequired 必填项属性, 输入框 input 添加了 required 必填项属性.
通过将 DTO 数据注解转换成标签的验证属性,可以让 Web Api 和 UI 的验证同步.
自定义验证
数据注解可以解决一些常见的验证场景.
但业务上可能需要编写自定义代码以更灵活的方式验证.
Util 应用框架定义了一个验证接口 Util.Validation.IValidation.
IValidation 接口定义了 Validate 方法,执行该方法返回验证结果集合.
实体,值对象,DTO 等对象类型实现了 IValidation 接口,意味着这些对象可以通过标准的 Validate 方法进行验证.
不论对象内部多么复杂,要验证它只需调用 Validate 方法即可.
验证逻辑被完全封装到对象内部.
DTO 自定义验证
DTO 参数对象 Validate 方法默认仅验证数据注解,如果有错误将抛出 Warning 异常.
Warning 异常代表业务错误,它的错误消息会返回给客户端.
Validate 是一个虚方法,可以进行重写.
TestDto 重写了 Validate 方法.
首先调用 base.Validate(); ,保证数据注解得到验证.
如果数据注解验证通过, 判断 Name 属性是否包含 test 字符串,如果包含则抛出 Warning 异常.
由于 DTO 参数仅用来传递数据,不应包含复杂的验证逻辑,通过重写 Validate 方法添加简单自定义验证逻辑应能满足需求.
另外, DTO 参数验证失败,可直接抛出 Warning 异常,让全局异常处理器进行处理.
领域对象自定义验证
领域对象包含实体和值对象等.
对于较复杂的业务场景,与 DTO 不同的是,领域对象可用于业务处理,而不是传递数据.
需要为领域对象提供更多的验证支持.
领域对象有多种方式进行自定义验证.
重写 Validate 方法
领域对象最简单的自定义验证方式是重写 Validate 方法,并提供额外的验证逻辑.
不过重写 Validate 验证方式也存在一些问题.
Validate 方法逐渐变得臃肿,代码稳定性在降低.
代码的清晰度很低,重要的验证条件属于业务规则,却被一堆杂乱的 if else 判断淹没了.
验证规则
验证规则 Util.Validation.IValidationRule 代表一个验证条件,接口定义如下.
/// <summary>
/// 验证规则
/// </summary>
public interface IValidationRule {
/// <summary>
/// 验证
/// </summary>
ValidationResult Validate();
}
可以为较复杂和重要的验证条件创建验证规则对象,把复杂的验证逻辑封装起来,并从领域对象中分离出来.
创建验证规则对象
约定: 验证规则对象需要取一个符合业务验证规则的名称, 并以 ValidationRule 结尾,文件放到 ValidationRules 目录中.
ValidationRule 结尾可能导致名称过长.
这里演示就随便起一个 SampleValidationRule.
验证规则依赖一些对象才能进行验证,如何才能获取依赖?
通过验证规则对象的构造方法传入需要的依赖对象.
验证规则不通过 Ioc 容器管理,在需要的地方通过 new 创建验证规则实例.
SampleValidationRule 示例构造方法只接收一个参数,但可以根据需要接收更多依赖项.
实现验证规则的 Validate 方法.
如果验证成功返回 ValidationResult.Success.
如果验证失败返回验证结果对象 ValidationResult, 并设置验证失败消息.
将验证规则添加到领域对象
领域对象基类定义了 AddValidationRule 方法,用于添加验证规则对象.
从领域对象外部调用 AddValidationRule 传入验证规则.
var entity = new TestEntity();
entity.AddValidationRule( new SampleValidationRule( entity ) );
可以通过工厂方法封装验证规则.
对于比较固定且只依赖领域对象本身的验证规则,可以在构造方法添加.
设置验证处理器
验证规则仅返回验证结果,验证失败如何处理由验证处理器决定.
领域对象默认的验证处理器在验证失败时抛出 Warning 异常.
你可以设置自己的验证处理器来替换默认的.
下面定义的 NothingHandler 在验证失败时什么也不做.
调用 SetValidationHandler 方法设置验证处理器.
var entity = new TestEntity();
entity.AddValidationRule( new SampleValidationRule( entity ) );
entity.SetValidationHandler( new NothingHandler() );
验证拦截器
Util 应用框架定义了几个用于验证的参数拦截器.
NotNullAttribute
验证是否为 null,如果为 null 抛出 ArgumentNullException 异常.
使用范例:
public interface ITestService : ISingletonDependency {
void Test( [NotNull] string value );
}
NotEmptyAttribute
使用 string.IsNullOrWhiteSpace 验证是否为空字符串,如果为空则抛出 ArgumentNullException 异常.
使用范例:
public interface ITestService : ISingletonDependency {
void Test( [NotEmpty] string value );
}
ValidAttribute
如果对象实现了 IValidation 验证接口,则自动调用对象的 Validate 方法进行验证.
使用范例:
验证单个对象.
public interface ITestService : ISingletonDependency {
void Test( [Valid] CustomerDto dto );
}
验证对象集合.
public interface ITestService : ISingletonDependency {
void Test( [Valid] List<CustomerDto> dto );
}
源码解析
DataAnnotationValidation 数据注解验证操作
可以调用 DataAnnotationValidation 的 Validate 方法验证数据注解.
ValidationResultCollection 验证结果集合
ValidationResultCollection 用于收集验证结果消息.
ThrowHandler 验证处理器
ThrowHandler 是默认的验证处理器,在验证失败时抛出 Warning 异常.
ValidAttribute 验证拦截器
ValidAttribute 是一个 Aop 参数拦截器,可以对实现了 IValidation 接口的单个对象或对象集合进行验证.
评论