博客 数据校验

数据校验

   蓝袋鼠   发表于 2025-04-18 10:33  73  0

校验介绍

一个应用的输入应该首先要验证。这个输入可以是用户的输入,也可以是另一个应用的输入。在一个Web应用中,验证通常要实现2次:第一次是客户端验证,第二次是服务端验证。客户端的验证是为了更好的用户体验,通过检测表单的字段来提醒用户必须的字段;服务端的验证是更严格且无法避免的。

服务端的验证是在应用服务层实现的。应用服务方法应该首先检查(验证)输入然后在使用。ABP提供了一个不错的基础设施来验证应用服务方法的输入。

输入服务方法以一个DTO对象作为输入参数。ABP提供了一个DTO可以实现的IValidate接口来自动验证它们。因为IInputDto扩展了IValidate,因此输入DTOs可以只实现IInput来确保验证。

使用数据注解

ABP支持数据注解,ABP通过MethodInvocationValidator对服务层方法参数拦截,需要实现验证的方法,使用ValidationInterceptor进行拦截。对应的源码在 Abp.Runtime.Validation.Interception命名空间。

现在我在CityInput文件中添加一个类CreateCityInput,代码如下:

http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/ffd07db532594cb344d883afae51bdfd..gif
public class CreateCityInput : IInputDto, IShouldNormalize
{
[Required]
public string Name { get; set; }
[Required]
public string Code { get; set; }
[Required]
public string ProvinceCode { get; set; }
public DateTime UpdatedTime { get; set; }
public string UpdatedBy { get; set; }

public void Normalize()
{
if (UpdatedTime==null)
{
UpdatedTime
=DateTime.Now;
}
}
}
http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/ffd07db532594cb344d883afae51bdfd..gif

CreateCityInput类实现了IInput和IShouldNormalize接口,并且在Name,Code,ProvinceCode是必填字段,最后实现了IShouldNormalize接口中的Normalize方法,判断了UpdatedTime是否为null,如果是null,就赋值为当前的时间。

在ICityAppService服务接口中添加方法:

void CreateCity(CreateCityInput input);

在CityAppService中实现该接口的此方法:

http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/ffd07db532594cb344d883afae51bdfd..gif
public void CreateCity(CreateCityInput input)
{
var city = _cityRepository.FirstOrDefault(c => c.Name == input.Name);
if (city != null)
{
throw new UserFriendlyException("该城市数据已经存在!");
}
city
= new Cities() { Code = input.Code, Name = input.Name, ProvinceCode = input.ProvinceCode };
_cityRepository.Insert(city);
}
http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/ffd07db532594cb344d883afae51bdfd..gif

在CityController中添加Create方法:

http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/ffd07db532594cb344d883afae51bdfd..gif
public ActionResult Create()
{
var input = new CreateCityInput()
{
Name
= "温州",
ProvinceCode
= "1",
Code
= "3",
};
_cityAppService.CreateCity(input);
return Content("OK");
}
http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/ffd07db532594cb344d883afae51bdfd..gif

这里,我们创建了一个CreateCityInput对象,并给三个必填字段赋值,然后调用服务接口的方法,如果服务方法执行成功,就向页面返回OK。

http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/95d5f45a86293d7e6716758464067fd2..png

http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/7b947e0124185a4a4a0b771e730c6790..png

方法执行成功,数据库中也成功添加了数据。

现在我们不给这三个必填字段之一赋值,修改CityController代码如下:

http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/ffd07db532594cb344d883afae51bdfd..gif
public ActionResult Create()
{
var input = new CreateCityInput()
{
Name
= "台州",
//ProvinceCode = "1",
Code = "3",
};
_cityAppService.CreateCity(input);
return Content("OK");
}
http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/ffd07db532594cb344d883afae51bdfd..gif

http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/c29529db11afd4d339ea5cfebac6954f..png

结果报错了,错误是“方法实参无效!请看验证错误细节。”可见,添加数据注解的属性因为不符合条件而产生的错误被成功拦截。ABP也会检测输入是否为null,如果为null,就抛出AbpValidationException异常。因此,不必写检测null的代码。如果输入的属性之一是无效的,也会抛出相同的异常。

这种机制和ASP.NET MVC的验证机制很相似,但是注意应用服务类不是派生自Controller类的,它是一个普通的类并且可以独立于web工作。

自定义验证

如果数据注解还不能满足你的需求的话,你也可以实现ICustomValidate接口:

http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/ffd07db532594cb344d883afae51bdfd..gif
public class CreateCityInput : IInputDto, IShouldNormalize,ICustomValidate
{
[Required]
public string Name { get; set; }
[Required]
public string Code { get; set; }
[Required]
public string ProvinceCode { get; set; }
public DateTime UpdatedTime { get; set; }
public string UpdatedBy { get; set; }

public void Normalize()
{
if (UpdatedTime==null)
{
UpdatedTime
=DateTime.Now;
}
}

public void AddValidationErrors(List results)
{
if (ProvinceCode.Length>5)
{
results.Add(
new ValidationResult("省份编码长度不能超过5个字符!"));
            throw new Exception("省份编码长度不能超过5个字符!");
}
}
}
http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/ffd07db532594cb344d883afae51bdfd..gif
http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/ffd07db532594cb344d883afae51bdfd..gif
public ActionResult Create()
{
var input = new CreateCityInput()
{
Name
= "衢州",
ProvinceCode
= "123456",
Code
= "4",
};
_cityAppService.CreateCity(input);
return Content("OK");
}
http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/ffd07db532594cb344d883afae51bdfd..gif

这里代码很简单,不用多做解释,(有问题的话直接评论区提问),直接测试一下。

http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/90d1904fc9d27016fe5b6b5f71b0ef82..png

 

标准化

标准化就是在验证之后,进行一些额外的操作。其实前面的代码已经标准化了,ABP定义了一个

具有Normalize方法的IShouldNormalize接口。如果实现了这个接口,Normalize方法就会在验证之后调用。正如之前的示例代码:

http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/ffd07db532594cb344d883afae51bdfd..gif
public void Normalize()
{
if (UpdatedTime==null)
{
UpdatedTime
=DateTime.Now;
}
}
http://dtstack-static.oss-cn-hangzhou.aliyuncs.com/2021bbs/files_user1/article/ffd07db532594cb344d883afae51bdfd..gif

这个作用就是,数据验证之后,如果UpdatedTime属性值为null,那么就把当前时间给它。当然,客户端传过来的数据也可能给UpdatedTime赋值,这样Normalize方法就不会执行了。

《数据资产管理白皮书》下载地址: https://www.dtstack.com/resources/1073/?src=bbs

《行业指标体系白皮书》下载地址: https://www.dtstack.com/resources/1057/?src=bbs

《数据治理行业实践白皮书》下载地址: https://www.dtstack.com/resources/1001/?src=bbs

《数栈V6.0产品白皮书》下载地址: https://www.dtstack.com/resources/1004/?src=bbs

想了解或咨询更多有关袋鼠云大数据产品、行业解决方案、客户案例的朋友,浏览袋鼠云官网: https://www.dtstack.com/?src=bbs

同时,欢迎对大数据开源项目有兴趣的同学加入「袋鼠云开源框架钉钉技术群」,交流最新开源技术信息,群号码:30537511,项目地址: https://github.com/DTStack

0条评论
社区公告
  • 大数据领域最专业的产品&技术交流社区,专注于探讨与分享大数据领域有趣又火热的信息,专业又专注的数据人园地

最新活动更多
微信扫码获取数字化转型资料
钉钉扫码加入技术交流群