Util应用框架基础(四) - 验证

这篇具有很好参考价值的文章主要介绍了Util应用框架基础(四) - 验证。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本节介绍Util应用框架如何进行验证.

概述

验证是业务健壮性的基础.

.Net 提供了一套称为 DataAnnotations 数据注解的方法,可以对属性进行一些基本验证,比如必填项验证,长度验证等.

Util应用框架使用标准的数据注解作为基础验证,并对自定义验证进行扩展.

基础用法

引用Nuget包

Nuget包名: Util.Validation.

通常不需要手工引用它.

数据注解

数据注解是一种.Net 特性 Attribute,可以在属性上应用它们.

常用数据注解

下面列出一些常用数据注解,如果还不能满足需求,可以创建自定义的数据注解.

  • RequiredAttribute 必填项验证

    [Required] 验证属性不能是空值.

    范例:

      public class Test {
          [Required]
          public string Name { get; set; }
      }
    

    [Required] 支持一些参数,可以设置验证失败的提示消息.

      public class Test {
          [Required(ErrorMessage = "名称不能为空")]
          public string Name { get; set; }
      }
    
  • StringLengthAttribute 字符串长度验证

    [StringLength] 可以对字符串长度进行验证.

    下面的例子验证 Name 属性的字符串最大长度为 5.

      public class Test {
          [StringLength(5)]
          public string Name { get; set; }
      }
    

    还可以同时设置最小长度.

    下面验证 Name 属性字符串最小长度为1,最大长度为 5.

      public class Test {
          [StringLength(5,MinimumLength = 1)]
          public string Name { get; set; }
      }
    
  • MaxLengthAttribute 字符串最大长度验证

    [MaxLength] 也可以用来验证字符串最大长度.

    验证 Name 属性的字符串最大长度为 5.

      public class Test {
          [MaxLength(5)]
          public string Name { get; set; }
      }
    
  • MinLengthAttribute 字符串最小长度验证

    [MinLength] 也可以用来验证字符串最小长度.

    验证 Name 属性的字符串最小长度为 1.

      public class Test {
          [MinLength(1)]
          public string Name { get; set; }
      }
    
  • RangeAttribute 数值范围验证

    [Range] 用于验证数值范围.

    下面验证 Money 属性的值必须在 1 到 5 之间的范围.

      public class Test {
          [Range( 1, 5 )]
          public int Money { get; set; }
      }
    
  • EmailAddressAttribute 电子邮件验证

    [EmailAddress] 用于验证电子邮件的格式.

      public class Test {
          [EmailAddress]
          public int Email { get; set; }
      }
    
  • PhoneAttribute 手机号验证

    [Phone] 用于验证手机号的格式.

      public class Test {
          [Phone]
          public int Tel { get; set; }
      }
    
  • IdCardAttribute 身份证验证

    [IdCard] 用于验证身份证的格式.

    它是一个Util应用框架自定义的数据注解.

      public class Test {
          [IdCard]
          public int IdCard { get; set; }
      }
    
  • UrlAttribute Url验证

    [Url] 用于验证网址格式.

      public class Test {
          [Url]
          public int Url { get; set; }
      }
    
  • RegularExpressionAttribute 正则表达式验证

    [RegularExpression] 可以使用正则表达式进行验证.

    由于正则表达式比较复杂,对于经常使用的场景,应封装成自定义数据注解.

    下面使用正则表达式验证身份证,可以封装到 [IdCard] 数据注解,从而避免正则表达式的复杂性.

      public class Test {
          [RegularExpression( @"(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)" )]
          public string IdCard { get; set; }
      }
    

验证数据注解

虽然在对象属性上添加了数据注解,但它们并不会自动触发验证.

你可以使用 Asp.Net Core 提供的方法验证对象上的数据注解.

Util 提供了一个辅助方法 Util.Validation.DataAnnotationValidation.Validate 用来验证数据注解.

DataAnnotationValidation.Validate 方法接收一个对象参数,只需将要验证的对象实例传入即可.

返回类型为验证结果集合,包含所有验证失败的消息.

    public class Test {
        [Required]
        public string Name { get; set; }

        public ValidationResultCollection Validate() {
            return DataAnnotationValidation.Validate( this );
        }
    }

大部分情况下,你并不需要调用 DataAnnotationValidation.Validate 方法验证数据注解.

实体,值对象,DTO等对象已经内置了 Validate 方法,它们会自动验证数据注解.

Util Angular UI 数据注解验证支持

Util Angular UI支持 Razor TagHelper服务端标签语法.

可以在表单组件使用 Lambda表达式绑定 DTO 对象属性.

TestDto参数对象 Name 属性使用 [Required] 设置必填项验证.

    public class TestDto : DtoBase {
        [Required]
        [Display(Name = "name")]
        public string Name { get; set; }
    }

Razor 页面声明 TestDto 模型, 定义输入框 util-input,使用 for 属性绑定到 TestDto 参数对象的 Name 属性.

@page
@model TestDto

<util-form>
    <util-input id="input_Name" for="Name" />
</util-form>

Razor页面最终会生成html,表单标签 nz-form-label 添加了 nzRequired 必填项属性, 输入框 input 添加了 required 必填项属性.

<form nz-form>
    <nz-form-item>
        <nz-form-label [nzRequired]="true">name</nz-form-label>
        <nz-form-control [nzErrorTip]="vt_input_Name">
            <input #input_Name="" #v_input_Name="xValidationExtend" name="name" nz-input="" x-validation-extend="" [(ngModel)]="model.name" [required]="true" />
            <ng-template #vt_input_Name="">{{v_input_Name.getErrorMessage()}}</ng-template>
        </nz-form-control>
    </nz-form-item>
</form>

通过将DTO数据注解转换成标签的验证属性,可以让 Web Api 和 UI 的验证同步.

自定义验证

数据注解可以解决一些常见的验证场景.

但业务上可能需要编写自定义代码以更灵活的方式验证.

Util应用框架定义了一个验证接口 Util.Validation.IValidation.

IValidation 接口定义了 Validate 方法,执行该方法返回验证结果集合.

/// <summary>
/// 验证操作
/// </summary>
public interface IValidation {
    /// <summary>
    /// 验证
    /// </summary>
    ValidationResultCollection Validate();
}

实体,值对象,DTO等对象类型实现了 IValidation 接口,意味着这些对象可以通过标准的 Validate 方法进行验证.

var entity = new TestEntity();
entity.Validate();

不论对象内部多么复杂,要验证它只需调用 Validate 方法即可.

验证逻辑被完全封装到对象内部.

DTO自定义验证

DTO参数对象 Validate 方法默认仅验证数据注解,如果有错误将抛出 Warning 异常.

Warning 异常代表业务错误,它的错误消息会返回给客户端.

Validate 是一个虚方法,可以进行重写.

    public class TestDto : DtoBase {
        [Required]
        public string Name { get; set; }

        public override ValidationResultCollection Validate() {
            base.Validate();
            if ( Name.Contains( "test" ) )
                throw new Warning( "名称不能包含test" );
            return ValidationResultCollection.Success;
        }
    }

TestDto 重写了 Validate 方法.

首先调用 base.Validate(); ,保证数据注解得到验证.

如果数据注解验证通过, 判断 Name 属性是否包含 test 字符串,如果包含则抛出 Warning 异常.

由于DTO参数仅用来传递数据,不应包含复杂的验证逻辑,通过重写 Validate 方法添加简单自定义验证逻辑应能满足需求.

另外, DTO参数验证失败,可直接抛出 Warning 异常,让全局异常处理器进行处理.

领域对象自定义验证

领域对象包含实体和值对象等.

对于较复杂的业务场景,与DTO不同的是,领域对象可用于业务处理,而不是传递数据.

需要为领域对象提供更多的验证支持.

领域对象有多种方式进行自定义验证.

  • 重写 Validate 方法

    领域对象最简单的自定义验证方式是重写 Validate 方法,并提供额外的验证逻辑.

        public class TestEntity : AggregateRoot<TestEntity> {
            public TestEntity() : this( Guid.Empty ) {
            }
            public TestEntity( Guid id ) : base( id ) {
            }
    
            [Required]
            public string Name { get; set; }
    
            public override ValidationResultCollection Validate() {
                base.Validate();
                if( Name.Contains( "test" ) )
                    throw new Warning( "名称不能包含test" );
                return ValidationResultCollection.Success;
            }
        }
    

    不过重写 Validate 验证方式也存在一些问题.

    • Validate 方法逐渐变得臃肿,代码稳定性在降低.

    • 代码的清晰度很低,重要的验证条件属于业务规则,却被一堆杂乱的 if else 判断淹没了.

  • 验证规则

    验证规则 Util.Validation.IValidationRule 代表一个验证条件,接口定义如下.

      /// <summary>
      /// 验证规则
      /// </summary>
      public interface IValidationRule {
          /// <summary>
          /// 验证
          /// </summary>
          ValidationResult Validate();
      }
    

    可以为较复杂和重要的验证条件创建验证规则对象,把复杂的验证逻辑封装起来,并从领域对象中分离出来.

    • 创建验证规则对象

      约定: 验证规则对象需要取一个符合业务验证规则的名称, 并以 ValidationRule 结尾,文件放到 ValidationRules 目录中.

      ValidationRule 结尾可能导致名称过长.

      这里演示就随便起一个 SampleValidationRule.

      验证规则依赖一些对象才能进行验证,如何才能获取依赖?

      通过验证规则对象的构造方法传入需要的依赖对象.

      验证规则不通过Ioc容器管理,在需要的地方通过 new 创建验证规则实例.

      SampleValidationRule 示例构造方法只接收一个参数,但可以根据需要接收更多依赖项.

      实现验证规则的 Validate 方法.

      如果验证成功返回 ValidationResult.Success.

      如果验证失败返回验证结果对象 ValidationResult, 并设置验证失败消息.

      public class SampleValidationRule : IValidationRule {
          private readonly TestEntity _entity;
      
          public SampleValidationRule( TestEntity entity ) {
              _entity = entity;
          }
      
          public ValidationResult Validate() {
              if( _entity.Name.Contains( "test" ) )
                  return new ValidationResult( "名称不能包含test" );
              return ValidationResult.Success;
          }
      }
      
    • 将验证规则添加到领域对象

      领域对象基类定义了 AddValidationRule 方法,用于添加验证规则对象.

      从领域对象外部调用 AddValidationRule 传入验证规则.

          var entity = new TestEntity();
          entity.AddValidationRule( new SampleValidationRule( entity ) );
      

      可以通过工厂方法封装验证规则.

      public class TestEntity : AggregateRoot<TestEntity> {
          public TestEntity() : this( Guid.Empty ) {
          }
          public TestEntity( Guid id ) : base( id ) {
          }
      
          [Required]
          public string Name { get; set; }
      
          public static TestEntity Create() {
              var entity = new TestEntity();
              entity.AddValidationRule( new SampleValidationRule( entity ) );
              return entity;
          }
      }
      
      var entity = TestEntity.Create();
      entity.Validate();
      

      对于比较固定且只依赖领域对象本身的验证规则,可以在构造方法添加.

      public class TestEntity : AggregateRoot<TestEntity> {
          public TestEntity() : this( Guid.Empty ) {
          }
      
          public TestEntity( Guid id ) : base( id ) {
              AddValidationRule( new SampleValidationRule( this ) );
          }
      
          [Required]
          public string Name { get; set; }
      }
      
    • 设置验证处理器

      验证规则仅返回验证结果,验证失败如何处理由验证处理器决定.

      /// <summary>
      /// 验证处理器
      /// </summary>
      public interface IValidationHandler {
          /// <summary>
          /// 处理验证错误
          /// </summary>
          /// <param name="results">验证结果集合</param>
          void Handle( ValidationResultCollection results );
      }
      

      领域对象默认的验证处理器在验证失败时抛出 Warning 异常.

      你可以设置自己的验证处理器来替换默认的.

      下面定义的 NothingHandler 在验证失败时什么也不做.

      /// <summary>
      /// 验证失败,不做任何处理
      /// </summary>
      public class NothingHandler : IValidationHandler {
          /// <summary>
          /// 处理验证错误
          /// </summary>
          /// <param name="results">验证结果集合</param>
          public void Handle( ValidationResultCollection results ) {
          }
      }
      

      调用 SetValidationHandler 方法设置验证处理器.

      var entity = new TestEntity();
      entity.AddValidationRule( new SampleValidationRule( entity ) );
      entity.SetValidationHandler( new NothingHandler() );
      

验证拦截器

Util应用框架定义了几个用于验证的参数拦截器.

  • NotNullAttribute

    • 验证是否为 null,如果为 null 抛出 ArgumentNullException 异常.

    • 使用范例:

      public interface ITestService : ISingletonDependency {
          void Test( [NotNull] string value );
      }
    
  • NotEmptyAttribute

    • 使用 string.IsNullOrWhiteSpace 验证是否为空字符串,如果为空则抛出 ArgumentNullException 异常.

    • 使用范例:

      public interface ITestService : ISingletonDependency {
          void Test( [NotEmpty] string value );
      }
    
  • ValidAttribute

    • 如果对象实现了 IValidation 验证接口,则自动调用对象的 Validate 方法进行验证.

    • 使用范例:

      验证单个对象.

      public interface ITestService : ISingletonDependency {
          void Test( [Valid] CustomerDto dto );
      }
    

    验证对象集合.

      public interface ITestService : ISingletonDependency {
          void Test( [Valid] List<CustomerDto> dto );
      }
    

源码解析

DataAnnotationValidation 数据注解验证操作

可以调用 DataAnnotationValidationValidate 方法验证数据注解.

/// <summary>
/// 数据注解验证操作
/// </summary>
public static class DataAnnotationValidation {
    /// <summary>
    /// 验证
    /// </summary>
    /// <param name="target">验证目标</param>
    public static ValidationResultCollection Validate( object target ) {
        if( target == null )
            throw new ArgumentNullException( nameof( target ) );
        var result = new ValidationResultCollection();
        var validationResults = new List<ValidationResult>();
        var context = new ValidationContext( target, null, null );
        var isValid = Validator.TryValidateObject( target, context, validationResults, true );
        if ( !isValid )
            result.AddList( validationResults );
        return result;
    }
}

ValidationResultCollection 验证结果集合

ValidationResultCollection 用于收集验证结果消息.

/// <summary>
/// 验证结果集合
/// </summary>
public class ValidationResultCollection : List<ValidationResult> {

    /// <summary>
    /// 初始化验证结果集合
    /// </summary>
    public ValidationResultCollection() : this( "" ) {
    }

    /// <summary>
    /// 初始化验证结果集合
    /// </summary>
    /// <param name="result">验证结果</param>
    public ValidationResultCollection( string result ) {
        if( string.IsNullOrWhiteSpace( result ) )
            return;
        Add( new ValidationResult( result ) );
    }

    /// <summary>
    /// 成功验证结果集合
    /// </summary>
    public static readonly ValidationResultCollection Success = new();

    /// <summary>
    /// 是否有效
    /// </summary>
    public bool IsValid => Count == 0;

    /// <summary>
    /// 添加验证结果集合
    /// </summary>
    /// <param name="results">验证结果集合</param>
    public void AddList( IEnumerable<ValidationResult> results ) {
        if( results == null )
            return;
        foreach( var result in results )
            Add( result );
    }

    /// <summary>
    /// 输出验证消息
    /// </summary>
    public override string ToString() {
        if( IsValid )
            return string.Empty;
        return this.First().ErrorMessage;
    }
}

ThrowHandler 验证处理器

ThrowHandler 是默认的验证处理器,在验证失败时抛出 Warning 异常.

/// <summary>
/// 验证失败,抛出异常
/// </summary>
public class ThrowHandler : IValidationHandler{
    /// <summary>
    /// 处理验证错误
    /// </summary>
    /// <param name="results">验证结果集合</param>
    public void Handle( ValidationResultCollection results ) {
        if ( results.IsValid )
            return;
        throw new Warning( results.First().ErrorMessage );
    }
}

ValidAttribute 验证拦截器

ValidAttribute 是一个 Aop 参数拦截器,可以对实现了 IValidation 接口的单个对象或对象集合进行验证.文章来源地址https://www.toymoban.com/news/detail-745924.html

/// <summary>
/// 验证拦截器
/// </summary>
public class ValidAttribute : ParameterInterceptorBase {
    /// <summary>
    /// 执行
    /// </summary>
    public override async Task Invoke( ParameterAspectContext context, ParameterAspectDelegate next ) {
        Validate( context.Parameter );
        await next( context );
    }

    /// <summary>
    /// 验证
    /// </summary>
    private void Validate( Parameter parameter ) {
        if ( Reflection.IsGenericCollection( parameter.RawType ) ) {
            ValidateCollection( parameter );
            return;
        }
        IValidation validation = parameter.Value as IValidation;
        validation?.Validate();
    }

    /// <summary>
    /// 验证集合
    /// </summary>
    private void ValidateCollection( Parameter parameter ) {
        if ( !( parameter.Value is IEnumerable<IValidation> validations ) )
            return;
        foreach ( var validation in validations )
            validation.Validate();
    }
}

到了这里,关于Util应用框架基础(四) - 验证的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Util应用框架 UI 开发快速入门

    本文是Util应用框架 Angular UI 开发快速入门教程. Util 应用框架目前仅支持用于开发管理后台的 UI. 本文介绍了 Util UI 的技术特点和功能支持. Js语言 TypeScript TypeScript 是 微软开发的脚本语言, 扩展了弱类型的 Javascript,提供增强的语法和强类型支持. 为编辑器代码提示和语法错误检

    2024年02月08日
    浏览(42)
  • Util应用框架快速入门(4) - 集成测试开发入门

    本文演示Util应用框架开发的项目中如何编写集成测试. 完成 Web Api 快速入门,本文将在之前生成的示例项目上讲解集成测试的开发. 自动化测试对于Util应用框架的开发非常重要,它能保证基础功能的稳定性. 对于使用 Util 开发的业务项目,自动化测试不是必须的,但掌握它可能很有

    2024年02月08日
    浏览(54)
  • 开源预训练框架 MMPRETRAIN官方文档(概览、环境安装与验证、基础用户指南)

    MMPretrain是全新升级的开源预训练框架。它已着手提供多个强大的预训练骨干网并支持不同的预训练策略。MMPretrain 源自著名的开源项目 MMClassification 和MMSelfSup,并开发了许多令人兴奋的新功能。目前,预训练阶段对于视觉识别至关重要。凭借丰富而强大的预训练模型,我们目

    2024年02月13日
    浏览(54)
  • Spring Boot框架基础介绍

    Spring Boot 是一款基于 Spring 框架的开源应用程序开发工具,它旨在简化 Spring 应用程序的配置和开发过程。Spring Boot 提供了一种简单的方式来创建可独立运行的、生产级别的应用程序,并在需要时进行部署。Spring Boot 在微服务架构和云计算环境下得到了广泛应用,本文将介绍

    2024年02月08日
    浏览(53)
  • SqlSugar框架之WPF应用端功能介绍

     WPF应用端是我们《SqlSugar开发框架》多端界面中的一部分,和Winform前端框架、Vue3+ElementPlus前端、UniApp+Thorn移动端,组成一个完整的整体框架,后端服务是基于SqlSugar的基础ORM的.netcore框架,提供Web API服务供各个前端使用,底层支持多种数据库,包括SqlServer、Oracle、Mysql、Po

    2024年02月08日
    浏览(42)
  • 视觉SLAM:模型介绍、算法框架及应用场景

    作者: 张长鸿 湖南大学 校稿: 董亚微 编辑: 郑欣欣@一点人工一点智能 原文地址: 视觉SLAM:模型介绍、算法框架及应用场景 目录 01 什么是SLAM  1.1 相机模型 1.2 相机运动 1.3 建图 02 SLAM算法框架 03 SLAM的应用场景 3.1 自动驾驶的高精度定位 3.2 自主移动机器人 知识扩展:

    2024年01月16日
    浏览(36)
  • WPF应用框架中工作流模块的介绍

    在前面的随笔,我对我们开发的审批工作流做了不少的介绍,其中有包括WInform的、Vue+Element、Bootstrap Asp.net的,在各个框架上,我们都尽量争取界面能够一致化,以便客户能够在不同的前端上有相同的用户体验,并结合不同的前端特点,做了一些优化处理,本篇随笔对WPF应用

    2024年02月05日
    浏览(40)
  • [框架设计] MVVM 的介绍,应用及优缺点

    MVVM(Model-View-ViewModel)是一种架构模式,用于将应用程序分离为三个部分: Model(模型):负责处理应用程序的数据和业务逻辑。 View(视图):负责呈现用户界面并处理用户交互。 ViewModel(视图模型):作为Model和View之间的中介,处理View的显示逻辑和用户交互,并将这些操

    2024年02月01日
    浏览(38)
  • JVS开源基础框架:平台基本信息介绍

    JVS是面向软件开发团队可以快速实现应用的基础开发脚手架,主要定位于企业信息化通用底座,采用微服务分布式框架,提供丰富的基础功能,集成众多业务引擎,它灵活性强,界面化配置对开发者友好,底层容器化构建,集合持续化构建。 JVS是定位为辅助研发团队的快速脚

    2024年02月12日
    浏览(52)
  • 实战演练|从原理到应用:DeepKE框架介绍及简单使用

    本文主要参考deepKE官方文档,以及deepKE官方框架源码https://github.com/zjunlp/DeepKE,我此时使用的DeepKE最新版本是2.1.1。 DeepKE是一个开源的知识图谱抽取与构建工具,支持 cnSchema、低资源、长篇章、多模态 的知识抽取工具,可以基于 PyTorch 实现 命名实体识别 、 关系抽取 和 属性

    2024年02月15日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包