本系列目录:Abp介绍和经验分享-目录

声明式的入参验证逻辑

声明式入参验证主要使用了System.ComponentModel.DataAnnotations中提供的各种验证参数的Attributes,将Attribute标记到属性上,即可(这是在早期Asp.Net Mvc中就支持的写法)。

例如:

public class DemoInputDto
{
[Required]
public int? Value1 { get; set; } [Range(0, int.MaxValue)]
public int Value2 { get; set; } [Required]
public DateTime? Time1 { get; set; } [RegularExpression("\\d+")]
public string RegMatchStr { get; set; }
}

以前都是配合Mvc控制器中的ModelState.IsValid即可判断参数是否验证通过。

而在ABP框架中,DTO的参数验证环节是通过IOC拦截器的机制在调用IApplicatonService接口的方法时进行验证的,如果验证不通过则会有相应的异常和错误信息输出。

稍复杂的情况,IValidatableObject,ICustomValidate

上面说的入参验证逻辑,仅限于DTO中的单个属性,如果入参验证逻辑需要针对一个DTO中的多个属性进行判断,就无法用声明式的方法去标记了。

这时,我们可以让InputDto继承IValidatableObjectICustomValidate,并实现验证逻辑,例如:

public class DemoInputDto : IValidatableObject
{
[Required]
public int? Value1 { get; set; } [Range(0, int.MaxValue)]
public int Value2 { get; set; } [Required]
public DateTime? Time1 { get; set; } [RegularExpression("\\d+")]
public string RegMatchStr { get; set; } public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (Value1 > 5 && Value2 < 100)
{
yield return new ValidationResult("blablabla", new string[] { "Value1", "Value2" });
}
}
}

public class DemoInputDto : ICustomValidate
{
///...略 public void AddValidationErrors(CustomValidationContext context)
{
if (Value1 > 5 && Value2 < 100)
{
context.Results.Add(new ValidationResult("blablabla", new string[] { "Value1", "Value2" }));
}
}
}

这两个接口用法差不多,差异在于:

  1. IValidatableObject接口是定义在System.ComponentModel.DataAnnotations命名空间中;
  2. ICustomValidate接口是ABP定义的,在Abp.Runtime.Validation命名空间中;

IValidatableObject如前所提,是Asp.Net Mvc框架原生支持的,而ABP框架同时支持这两个接口。

Tips,如果你打算直接拿应用层的DTO直接作为Mvc Action上的入参,建议用IValidatableObject。

多个DTO重用验证逻辑,OOP多态

最后这点是我自己的经验分享。

有时候,某个应用服务(例如MySettingAppService)的多个方法的InputDto含有一批类似的属性,并且有一样的入参验证逻辑。

比如一个场景,有个业务制定了等级机制,进行配置时,每个配置方法都需要针对所有等级进行配置,并且不允许针对单个等级进行配置,以防遗漏某个等级未配置。

///第一个Dto,假设叫ADto
///等级Id作为字典key,配置值是简单数字
public Dictionary<int, int> LevelGenerationCountList { get; set; } ///...
///第二个Dto,假设叫BDto
///等级Id作为字典key,配置值为value
public Dictionary<int, decimal> LevelMinimumConsuptionList { get; set; }

如果我想简单验证这两个DTO的入参是否都满足当前等级数量的要求,验证逻辑可能要重复写成这样:

public class MySettingAppService : MyAppServiceBase, IMySettingAppService
{
///...略 private async Task CheckLevelSettingsCount(ADto input)
{
if (!await _levelSettingPolicy.Satisfied(input.LevelGenerationCountList.Count))
{
throw new Abp.UI.UserFriendlyException("必须为当前所有等级提供配置!");
}
} private async Task CheckLevelSettingsCount(BDto input)
{
if (!await _levelSettingPolicy.Satisfied(input.LevelMinimumConsuptionList.Count))
{
throw new Abp.UI.UserFriendlyException("必须为当前所有等级提供配置!");
}
}
}

DRY,这种重复代码必须消灭掉!怎么动手?OOP 多态!

自定义一个IHasLevelSettingCount,如下:

public interface IHasLevelSettingCount
{
int GetLevelSettingCount();
}

ADto和BDto都继承IHasLevelSettingCount:

public class ADto:IHasLevelSettingCount
{
///...略
public int GetLevelSettingCount()
{
return LevelGenerationCountList.Count;
}
} public class BDto:IHasLevelSettingCount
{
///...略
public int GetLevelSettingCount()
{
return LevelMinimumConsuptionList.Count;
}
}

MySettingAppService就只需要写一个CheckLevelSettingsCount:

public class MySettingAppService : MyAppServiceBase, IMySettingAppService
{
///...略
private async Task CheckLevelSettingsCount(IHasLevelSettingCount input)
{
if (!await _levelSettingPolicy.Satisfied(input.GetLevelSettingCount()))
{
throw new Abp.UI.UserFriendlyException("必须为当前所有等级提供配置!");
}
}
}

这样,借助多态,CheckLevelSettingsCount 既可以传入ADto,又可以传入BDto,实现了验证逻辑的复用,消灭了重复代码!

最新文章

  1. oracle(sql)基础篇系列(一)&mdash;&mdash;基础select语句、常用sql函数、组函数、分组函数
  2. Git 冲突合并
  3. centos6 install mcrypt
  4. 在ABP模板工程中使用MySql
  5. 【ASM C/C++】 Makefile 规则说明
  6. Request三种获取数据的方式
  7. web项目中的跨域问题解决方法
  8. Octopus系列之UploadValues异步上载
  9. 【转】10.4新特性-ArcGIS 10.4矢量切片介绍
  10. Akka.net开发第一个分布式应用
  11. 基于 HTML5 Canvas 的交互式地铁线路图
  12. 手把手带你走进MVP +Dagger2 + DataBinding+ Rxjava+Retrofit 的世界
  13. 16进制字符串转QByteArray,char转16进制字符串
  14. Python内置函数(62)——sum
  15. 什么是面向切面编程AOP
  16. [工控安全]西门子S7-400 PLC固件逆向分析(一)
  17. 包建强的培训课程(4):App测试深入学习和研究
  18. Python使用MySQL数据库【转】
  19. css3 @media 实现响应式布局
  20. css之hover改变子元素和其他元素样式

热门文章

  1. 洛谷——P2706 巧克力
  2. sort、dirname、添加环境变量、修改主机名、别名IP、静态路由
  3. app 检查更新和更新
  4. iphone坐标系统
  5. CD_Lulu软件著作权中软件分类号
  6. C# 通过WebService方式 IIS发布网站 上传文件到服务器[转]
  7. Python 实现二维码生成和识别
  8. 全文索引-lucene,solr,nutch,hadoop之nutch与hadoop
  9. java实验8-Java输入输出流
  10. .net 4.0 网站发布(转)