📚
Hoa Framework
  • 一、框架指南
  • 二、功能特性
  • 三、源码结构
  • 四、代码规范
  • 五、入门指南
  • 六、依赖注入/控制反转
  • 七、控制器和服务
  • 八、对象映射指南
  • 九、数据库操作指南
    • 9.1、正向工程(Code First)
    • 9.2、逆向工程(Database First)
    • 9.3、关于仓储(IRepository)
    • 9.4、增删改操作
    • 9.5、查询操作
    • 9.6、DataSet、DataTable 操作
    • 9.7、查询结果集映射
    • 9.8、批量增删改操作
    • 9.9、存储过程、视图、函数操作
    • 9.10、工作单元和事务
    • 9.11、多上下文、读写分离
    • 9.12、切面上下文(TangentDbContext)
    • 9.13、其他操作
    • 9.14、EF Core 高性能
    • 9.15、常见错误
  • 十、开放接口指南
    • 10.1、RESTFul 和 Swagger
    • 10.2、规范化返回值
  • 十一、数据校验
  • 十二、安全授权
  • 十三、异常处理
  • 十四、日志管理
  • 十五、配置管理
  • 十六、缓存管理
  • 十七、内置工具类
    • 17.1、数据加解密
  • 十八、跨域处理
  • 十九、筛选拦截器(未)
  • 二十、进程服务(Daemon)
  • 二十一、编写测试
    • 20.1、单元测试
    • 20.2、基准测试
    • 20.3、性能测试
  • 二十二、托管部署
    • 22.1、IIS 托管部署
    • 22.2、Nginx 托管部署
    • 22.3、Docker 容器部署
  • 二十三、性能分析(MiniProfiler)
  • 二十四、其他功能
    • 23.1、第三方包管理
    • 23.2、文件上传下载
    • 23.3、Razor 视图引擎
    • 23.4、生成客户端请求代码
    • 23.5、快捷操作
  • 二十五、Docker 容器化
    • 25.1、Docker 介绍
    • 25.2、Docker 安装
    • 25.3、Docker 安装服务
    • 25.4、Docker 常用命令
    • 25.6、Docker run 常用命令
    • 25.7、Docker-Compose 介绍
    • 25.8、docker-compose.yml
    • 25.9、Docker-Compose 常用命令
    • 25.10、Docker-Compose 转换 docker run
    • 25.11、Docker 构建自己的镜像
    • 25.12、Dockerfile指南
    • 25.13、Dockerfile 常用命令
    • 25.14、Dockerfile 打包、上传、分享
    • 25.15、Docker 数据卷
    • 25.16、Docker 域网络
    • 25.17、Docker + Nginx 实现分布式集群、负载均衡
  • 二十六、DevOps 持续部署集成
    • 26.1、DevOps 介绍
    • 26.2、持续集成、交付、部署
    • 26.3、Jenkins 介绍
    • 26.4、Jenkins 安装
    • 26.5、Jenkins 初始化
    • 26.6、Jenkins 实战演练
    • 26.7、Jenkis 项目配置
    • 26.8、Jenkins 插件
  • 二十七、OpenXml/Excel 操作
  • 二十八、SaaS 多租户
  • 二十九、Git 代码管理
    • 29.1、Git 介绍
    • 29.2、Git 安装
    • 29.3、Git 基础配置
    • 29.4、Git 工作流程
    • 29.5、Git 重要概念
    • 29.6、Git 创建仓库
    • 29.7、Git 基本操作
    • 29.8、Git 分支管理
    • 29.9、Git 查看提交历史
    • 29.10、Git 标签
    • 29.11、Git 拉取/获取/推送
    • 28.12、Git GUI工具
    • 29.13、Git 私有化部署
    • 29.14、Git 推荐开发模式
    • 29.15、Svn 转 Git
  • 贡献代码
  • 更新日志
由 GitBook 提供支持
在本页
  • 数据校验介绍
  • 数据校验好处
  • 数据校验三种方式
  • 常见方式(不推荐)
  • 特性注解方式(推荐)
  • asp.net core 内置验证特性
  • 自定义验证特性
  • IValidatableObject 方式
  • FluentValidation(推荐)
  • 跳过验证
  • 特别说明

这有帮助吗?

十一、数据校验

一套安全的系统应该对所有使用者提交的数据进行安全校验。

数据校验介绍

数据校验字面上的意思就是对使用者提交过来的数据进行合法性验证。在一套完善的应用系统中,数据有效性校验是必不可少的第一道关卡。

数据校验好处

  1. 过滤不安全数据,提高系统的安全性

  2. 减少不必要的业务异常处理,提高系统的响应速度

  3. 大大提高系统稳定性

  4. 大数据并发时起着一定的缓冲作用

数据校验三种方式

  • 常见方式,在业务代码中编写验证逻辑

  • 特性方式,在参数或属性中贴特性

  • FluentValidation 方式,支持链式验证

常见方式(不推荐)

在过去的开发中,我们常常把数据校验写在业务代码的顶部,比如:

public bool Insert(Person person)
{
    // 验证参数
    if(string.IsNullOrEmty(person.Name))
    {
        throw new System.Exception("名字不能为空");
    }
    
    if(person.Age < 18)
    {
        throw new System.Exception("年龄不能小于 18 岁");
    }
    
    if(!person.Password.Equals(person.ConfirmPassword){
        throw new System.Exception("两次密码不一致");
    }
    
    // 业务代码
    _testRepository.Insert(person.Adapt<PersonEntity>());
    
    // ...
}

从上面的代码看起来,似乎没有什么不妥,但是从一个程序可维护性来说,这是一个糟糕的代码,因为该业务代码中包含了太多与业务无关的数据验证。

试想一下,如果这个 Person 有 几十个参数都需要验证呢?可想而知,这是一个庞大的业务代码。

再者,如果其他地方也需要用到这个 Person 类验证呢?那代码好比老鼠啃过的面包屑一样,到处都是。

如此得知,这样的方式是极其不推荐的,不但污染了业务代码,也破坏了业务职责单一性原理,也让验证逻辑无法实现通用,后续维护难度大大升级。

所以,我们迫切需要一种新的方式去解决上述问题。

特性注解方式(推荐)

微软提供了 System.ComponentModel.DataAnnotations 组件可通过特性方式实现数据模型进行元数据验证。完整的将数据校验和业务代码剥离开来,而且极易使用和自定义拓展。如:

using System.ComponentModel.DataAnnotations;

namespace Hoa.Application.Authorization.Dtos
{
    public class SignInInput
    {
        [Required]  // 必填验证
        [MinLength(4)]  // 最小长度验证
        public string Account { get; set; }

        [Required]    // 必填验证
        [MaxLength(32)]    // 最大长度验证
        public string Password { get; set; }
    }
}

除了在模型中实现特性方式验证,还可以在方法参数中实现验证,如:

public void CheckMethodParameterVaild(
    [Required]    // 必填验证
    [MinLength(4)]    // 最小长度验证
    string name,
    int age,
    [Required]    // 必填验证
    [RegularExpression("[a-zA-Z0-9_]{8,30}")    // 正则表达式验证
    string password,
    [Required]    // 必填验证
    [RegularExpression("[a-zA-Z0-9_]{8,30}")    // 正则表达式验证
    string confirmPassword
)
{
    // TODO
}

特别申明:如果函数的参数大于或等于3个,建议抽离出模型类,也就是不建议上面的方式。

在 asp.net core 中,微软提供了这种极其灵活的特性验证方式验证数据,大大的减少了业务代码的复杂度,又能实现业务代码和验证解耦。

asp.net core 内置验证特性

  • [Required]:必填

  • [MinLength(20)]:最小长度

  • [MaxLength(20)]:最大长度

  • [StringLength(20)]:字符串最大长度

  • [EmailAddress]:验证电子邮件格式

  • [Phone]:验证手机号码

  • [Range]:验证是否在指定范围

  • [Compare(nameof(Value))]:校对属性是否一致

  • [Url]:判断是否是 Url 地址

  • [RegularExpression]:正则表达式

自定义验证特性

除了内置的这些验证特性以外,asp.net core 还提供了一种自定义验证特性方式,这样我们就可以抽离出一些通用的验证特性了。如新增 [Custom] 验证特性

public class CustomAttribute : ValidationAttribute
{
    public CustomAttribute(object param)
    {
        Param = param;
    }

    public object Param { get; }    // 你的额外参数

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var obj =validationContext.ObjectInstance;

        if (你的逻辑)
        {
            return new ValidationResult("错误消息");
        }

        return ValidationResult.Success;
    }
}
public class MyClass
{
    [Custom]
    public string MyData { get; set; }
}

IValidatableObject 方式

另外,asp.net core 还提供了接口验证模式,通常这样的模式用于不通用的验证模型,也就是特定类的特定验证。这种验证方式只需要在模型类中实现 IValidatableObject 接口即可。如:

public class DtoModel : IValidatableObject
{

    [Required]
    [StringLength(100)]
    public string Title { get; set; }

    // 你的验证逻辑
    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (你的逻辑代码)
        {
            yield return new ValidationResult(
                "错误消息"
                ,new[] { nameof(Title) }  // 验证失败的属性
            );    
        }
    }
}

FluentValidation(推荐)

FluentValidation 内置丰富的链式验证,提供 AOP 面向切面方式验证,不干扰业务代码,不污染业务模型,是数据校验最佳实现方式。如:

using FluentValidation;

namespace Hoa.Application.Authorization.Dtos
{
    public class SignInInput
    {
        public string Account { get; set; }
        
        public string Password { get; set; }
    }

    // FluentValidation配置
    public class SignInInputValidator : AbstractValidator<SignInInput>
    {
        public SignInInputValidator()
        {
            RuleFor(u => u.Password).NotNull().NotEmpty().WithMessage("密码不能为空")
                .MaximumLength(32).WithMessage("密码长度不能超过32位");
        }
    }
}
using FluentValidation;
using System.ComponentModel.DataAnnotations;

namespace Hoa.Application.Authorization.Dtos
{
    public class SignInInput
    {
        [Required]
        [MinLength(4)]
        public string Account { get; set; }

        [Required]
        [MinLength(6)]
        public string Password { get; set; }
    }

    // FluentValidation配置
    public class SignInInputValidator : AbstractValidator<SignInInput>
    {
        public SignInInputValidator()
        {
            RuleFor(u => u.Password).NotNull().NotEmpty().WithMessage("密码不能为空")
                .MaximumLength(32).WithMessage("密码长度不能超过32位");
        }
    }
}

跳过验证

只需要在方法或类上面贴 [NotVaild] 特性即可。

特别说明

在 Hoa Framework 中,不管是哪一种验证方式,框架内部都实现了自动验证,无需程序员手动干涉验证。也就是无需调用如下代码:

if(!ModelState.IsVaild)
{
    // ....
}
上一页10.2、规范化返回值下一页十二、安全授权

最后更新于4年前

这有帮助吗?

关于更多内置的 asp.net core 模型验证。

在开发一套复杂的应用系统时,我们的数据校验可能非常复杂,比如涉及到场景验证、验证结果多语言控制、能够在验证之前和之后编写逻辑等等。这时,asp.net core 内置的验证方式很难满足我们的需求,所以,这里推荐使用一个非常优秀的第三方组件 。

另外, 也兼容asp.net core 内置的模型验证方式,也就是可以实现共同作用:

在这里,就不多介绍 验证方式了,更多 。

可查看官方文档
FluentValidation
FluentValidation
FluentValidation
FluentValidation
可查看官方文档