本系列目录: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,实现了验证逻辑的复用,消灭了重复代码!

[2017-10-26]Abp系列——DTO入参验证使用方法及经验分享的更多相关文章

  1. 2017.10.26 JavaWeb----第五章 JavaBean技术

    JavaWeb----第五章 JavaBean技术 (1)JavaBean技术 JavaBean技术是javaweb程序的重要组成部分,是一个可重复使用的软件组件,是用Java语言编写的.遵循一定的标 ...

  2. 2017.10.26 ECN + product spec+ cypress ble module test+

    1 ECN Ecn  should be issued when modifying drawing,Copy children BOM of subassembly from BIL if one ...

  3. 2017.10.28 针对Java Web应用中错误异常处理方法的运用

    针对Java Web应用中错误异常处理方法的运用 在javaweb中其异常都需要对Checked Exception之下的Exception进行继承,并且有选择地对发生的错误和异常进行处理.Java同 ...

  4. paper 10:支持向量机系列七:Kernel II —— 核方法的一些理论补充,关于 Reproducing Kernel Hilbert Space 和 Representer Theorem 的简介。

    在之前我们介绍了如何用 Kernel 方法来将线性 SVM 进行推广以使其能够处理非线性的情况,那里用到的方法就是通过一个非线性映射 ϕ(⋅) 将原始数据进行映射,使得原来的非线性问题在映射之后的空间 ...

  5. 2017/10 冲刺NOIP集训记录:暁の水平线に胜利を刻むのです!

    前几次集训都没有记录每天的点滴……感觉缺失了很多反思的机会. 这次就从今天开始吧!不能懈怠,稳步前进! 2017/10/1 今天上午进行了集训的第一次考试…… 但是这次考试似乎是近几次我考得最渣的一次 ...

  6. 欢迎来怼——第14次Scrum会议(10/26)

    一.小组信息 队名:欢迎来怼小组成员队长:田继平成员:李圆圆,葛美义,王伟东,姜珊,邵朔,冉华 小组照片 二.开会信息 时间:2017/10/26  17:00~17:13(总计13min).地点:计 ...

  7. ABP(现代ASP.NET样板开发框架)系列之10、ABP领域层——实体

    点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之10.ABP领域层——实体 ABP是“ASP.NET Boilerplate Project (ASP.NET样板 ...

  8. 九月 26, 2017 10:18:14 上午 com.sun.jersey.server.impl.application.RootResourceUriRules <init> 严重: The ResourceConfig instance does not contain any root resource classes.

    Tomcat启动错误:九月 26, 2017 10:18:14 上午 com.sun.jersey.server.impl.application.RootResourceUriRules <i ...

  9. 浅入 ABP 系列(4):事件总线

    浅入 ABP 系列(4):事件总线 版权护体作者:痴者工良,微信公众号转载文章需要 <NCC开源社区>同意. 目录 浅入 ABP 系列(4):事件总线 事件总线 关于事件总线 为什么需要这 ...

随机推荐

  1. LeetCode OJ--Search Insert Position

    https://oj.leetcode.com/problems/search-insert-position/ 数组有序,给一个数,看它是否在数组内,如果是则返回位置,如果不在则返回插入位置. 因为 ...

  2. 回调函数 typedef bool (*IsUsed)(const string &name,boost::shared_ptr<ShpGeometry> oneGeometry);

    就是指向函数的指针. 回调函数,表示了一个函数的地址,将函数作为参数进行使用.参考百度百科:http://baike.baidu.com/view/414773.htm 常用的大概就是在sort函数中 ...

  3. AC日记——让我们异或吧 洛谷 P2420

    题目描述 异或是一种神奇的运算,大部分人把它总结成不进位加法. 在生活中…xor运算也很常见.比如,对于一个问题的回答,是为1,否为0.那么: (A是否是男生 )xor( B是否是男生)=A和B是否能 ...

  4. echarts 金字塔

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. chpasswd、dd命令、find实战、添加系统服务、buffer、cached

    1.如果两个文件的每一行想一一对应 paste 1.txt 2.txt # 文件3.txt中存放着用户跟密码,想要添加用户并设置密码: # 用户必须存在,文件格式必须是--用户名:密码 chpassw ...

  6. Oracle PL/SQL 存储过程、函数、包 的范例

    1,写函数和过程,输入三角形三个表的长度.在控制台打印三角形的面积 -- 创建包 create or replace package pac_area is -- 定义计算三角形面积的过程 proce ...

  7. eclipse中通过search打开第二个文件时 第一个文件就自己关闭了

    原文:http://blog.csdn.net/u014079773/article/details/66971053 问题:eclipse中通过search打开第二个文件时第一个文件就自己关闭了 问 ...

  8. mysql 导入sql文件时自动切换了大小写

    windows环境下: 解决办法(即将其改为大小写敏感): 在my.ini中添加 lower_case_table_names=1

  9. eclipse从svn检出项目

    在eclipse的project explorer 右键->import->svn->从svn检出项目,然后填写资源库的位置,完成,然后一直next. 直到项目检出完成后,选择项目, ...

  10. 无线热点登陆认证原理探究---captive portal

    什么是Captive Portal 大家肯定都连过公共场所的wifi热点,比如麦当劳等地方的.他们的wifi往往一连上去就会弹出一个要求登录或者微信关注之类的页面,只有在这个页面完成操作了才能正常访问 ...