[2017-10-26]Abp系列——DTO入参验证使用方法及经验分享
本系列目录: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继承IValidatableObject
或ICustomValidate
,并实现验证逻辑,例如:
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" }));
}
}
}
这两个接口用法差不多,差异在于:
IValidatableObject
接口是定义在System.ComponentModel.DataAnnotations
命名空间中;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入参验证使用方法及经验分享的更多相关文章
- 2017.10.26 JavaWeb----第五章 JavaBean技术
JavaWeb----第五章 JavaBean技术 (1)JavaBean技术 JavaBean技术是javaweb程序的重要组成部分,是一个可重复使用的软件组件,是用Java语言编写的.遵循一定的标 ...
- 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 ...
- 2017.10.28 针对Java Web应用中错误异常处理方法的运用
针对Java Web应用中错误异常处理方法的运用 在javaweb中其异常都需要对Checked Exception之下的Exception进行继承,并且有选择地对发生的错误和异常进行处理.Java同 ...
- paper 10:支持向量机系列七:Kernel II —— 核方法的一些理论补充,关于 Reproducing Kernel Hilbert Space 和 Representer Theorem 的简介。
在之前我们介绍了如何用 Kernel 方法来将线性 SVM 进行推广以使其能够处理非线性的情况,那里用到的方法就是通过一个非线性映射 ϕ(⋅) 将原始数据进行映射,使得原来的非线性问题在映射之后的空间 ...
- 2017/10 冲刺NOIP集训记录:暁の水平线に胜利を刻むのです!
前几次集训都没有记录每天的点滴……感觉缺失了很多反思的机会. 这次就从今天开始吧!不能懈怠,稳步前进! 2017/10/1 今天上午进行了集训的第一次考试…… 但是这次考试似乎是近几次我考得最渣的一次 ...
- 欢迎来怼——第14次Scrum会议(10/26)
一.小组信息 队名:欢迎来怼小组成员队长:田继平成员:李圆圆,葛美义,王伟东,姜珊,邵朔,冉华 小组照片 二.开会信息 时间:2017/10/26 17:00~17:13(总计13min).地点:计 ...
- ABP(现代ASP.NET样板开发框架)系列之10、ABP领域层——实体
点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之10.ABP领域层——实体 ABP是“ASP.NET Boilerplate Project (ASP.NET样板 ...
- 九月 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 ...
- 浅入 ABP 系列(4):事件总线
浅入 ABP 系列(4):事件总线 版权护体作者:痴者工良,微信公众号转载文章需要 <NCC开源社区>同意. 目录 浅入 ABP 系列(4):事件总线 事件总线 关于事件总线 为什么需要这 ...
随机推荐
- Python Challenge 第一关
偶然在网上看到这个,PYTHON CHALLENGE,利用Python语言闯关,觉得挺有意思,就记录一下. 第0关应该算个入口吧,试了好几次才试出来,没什么代码就不写了.计算一个结果出来就行. 第一关 ...
- AC日记——软件包管理器 洛谷 P2416
题目描述 Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个 ...
- Objective_C与Swift混编遇到的坑(一)
swift推出已经很长一段时间了,前段时间突然想尝试一些简单的类用swift编写于是便开始了混编的路程. 1.在oc代码里引用swift类:找了很多资料需要添加头文件格式为 #import " ...
- Excel文件处理Demo
1.BLL业务逻辑代码 /// <summary> /// 处理“店铺竞品销售数据”导入文件 /// </summary> /// <param name="f ...
- webpack 学习笔记 03 Code Splitting
Introduction 对于较大的web 应用来说,将所有的代码文件压缩成一个文件是不合适的,在部分代码文件只有特殊情况下才被需要的情况下,这无疑是一种浪费.webpack 提供了讲代码文件分块的能 ...
- C语言变长数组 struct中char data[0]的用法
版权声明:本文为博主原创文章,未经博主允许不得转载. 今天在看一段代码时出现了用结构体实现变长数组的写法,一开始因为忘记了这种技术,所以老觉得作者的源码有误,最后经过我深思之后,终于想起以前看过的用s ...
- servelet
获取页面传递过来的参数. 调用后台代码实现相关业务逻辑. 根据返回结果,进行页面跳转. 问题:httpsession? 拆解: String 里面的.spllit方法.拆开后,返回值为string ...
- mac os PHP 访问MSSQL
写在前: 项目的数据库是sql server,但是自己的系统是mac os.这样导致了需要一个烦人的系统环境搭建过程.目前要在mac 上的php环境中支持mssql环境访问,经过自己了解,有两种方式: ...
- Django小项目练习
Django学生管理系统 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^class_list/', views.class_list ...
- MySQL的timeout那点事
http://www.mysqlops.com/2011/11/24/mysql_timeout.html