团队校验组件 - Xxx.BI.Validate

一、基础说明

1.开发这个组件的背景

线上系统经常遇到以下情况:
- 某个字段由必填切换成非必填
- DB的长度不能满足目前业务,比如由 30的长度 调整为 50
- 正则表达式之类的校验需要 扩充

当遇到类似上述情况时,基本都要重新修改代码,重新测试走发布流程,有时候还需要合并不同版本的代码(1.风险高 2.紧急情况时效无法保证)等;开发这个基于Database的校验组件(配置信息第一版本基于服务器内存进行缓存)是为了能够很方便的适应上述需求.

2.提示消息持的占位符

{FieldName} :字段名称占位符
{InputValue} :校验的输入值
{ValidValue} :有效值

3.校验组件使用的相关特性

Xxx.BI.Validate.ValidateFieldAttribute :核心校验特性
Xxx.Attributes.AliasAttribute : 别名特性

4.全局校验的默认格式

校验类型格式化字符串返回给用户的校验结果示例
Required{FieldName} is required.年龄 is required.
MaxLength{FieldName} maxlength is {ValidValue},the value {InputValue} invalid.手机号码 maxlength is 11,the value 086-15821573438 invalid.
DecimalDigitsLength{FieldName} decimal digits is {ValidValue},the value {InputValue} invalid.D0 decimal digits is 0,the value 12.1 invalid.
RangString{FieldName} valid value must be contains in {ValidValue},the value {InputValue} invalid.R1 valid value must be contains in
RegexExpression{FieldName} -> the value {InputValue} invalid.英文名 -> the value 苹果 invalid.

4.已实现的功能

1.基于	Xxx.BI.Validate.ValidateFieldAttribute 配置的校验
2.基于 Database (支持MySQL、SQL Server) 配置的校验

   以上 两种都配置,优先使用Database配置,非database会失效

二、仅配置 ValidateFieldAttribute 实现校验

1.仅ValidateFieldAttribute 特性配置说明

名称类型默认值说明
Keystring校验唯一Key,不使用 对应 Sys_Validate_Field 表中的 Validate_Key 字段的值;
Remarkstring备注,显示作用,无任何业务逻辑
CSharpDataTypeenumString数据类型,在database中配置的时候不区分大小写;支持的枚举 -> [ Int,Long,String,Datetime,Decimal ]
Requiredboolfalse是否必填;true:启用必填校验;false:禁用必填校验
MaxLengthint-1最大长度,小于等于0 则不生效此校验
DecimalDigitsLengthint-1小数位数长度校验,小于等于-1则不生效此校验
RegexExpressionstring正则表达式消息
RegexExpressionMsgstringRegexExpression字段对应的提示消息
RangeStringstring范围; 1.字符串类型的范围校验配置用 | 隔开,开头和结尾不能省略,如: |男|女| . 2. 数字类型的范围,支持Int、Long、Decimal 类型,配置示例介绍 -> 1~99 ,表示大于等于1小于等于99;1~ 表示大于等于1;~ 99 表示小于等于 99 范围校验必须指定 CSharpDataType

2.仅配置ValidateFieldAttribute使用示例

2.1 实体配置

using Xxx.Attributes;

namespace Xxx.BI.ValidateField.NUnit.DemoModel
{
    /// <summary>
    /// 没有数据库这种情况的校验配置
    /// </summary>
    /// <remarks>
    /// <para/>Author   :  AnDequan
    /// <para/>Date     :  2021-05-19 14:58
    /// </remarks>
    public class NoDbValidateConfig
    {

        /// <summary>
        /// 订单编号
        /// </summary>
        [ValidateField(CSharpDataType = EnumCSharpDataType.String, Required = true, MaxLength = 30)]
        [Alias("订单编号")]
        public string OrderNo { get; set; }

        /// <summary>
        /// Code
        /// </summary>
        [ValidateField(CSharpDataType = EnumCSharpDataType.String, Required = true, MaxLength = 30)]
        [Alias("系统唯一代码")]
        public string Code { get; set; }

        /// <summary>
        /// 中文名称
        /// </summary>
        [ValidateField(CSharpDataType = EnumCSharpDataType.String, MaxLength = 50)]
        public string NameCn { get; set; }

        /// <summary>
        /// 英文名称,只能输入英文字母
        /// </summary>
        [ValidateField(CSharpDataType = EnumCSharpDataType.String, RegexExpression = "^[A-Za-z]+$", RegexExpressionMsg = "{FieldName} invalid.")]
        public string NameEn { get; set; }

        /// <summary>
        /// 单价
        /// </summary>
        [ValidateField(CSharpDataType = EnumCSharpDataType.Decimal, MaxLength = 19, DecimalDigitsLength = 5)]
        public decimal? Price { get; set; }
    }
}

2.2 调用获取校验结果示例

using NUnit.Framework;
using System.Collections.Generic;
using Xxx.AuxiliaryEntity;
using Xxx.BI.ValidateField;
using Xxx.BI.ValidateField.NUnit.DemoModel;

namespace Xxx.BI.Validate.NUnit
{
    /// <summary>
    /// 验证Demo
    /// </summary>
    /// <remarks>
    /// <para/>Author   :  AnDequan
    /// <para/>Date     :  2021-05-19 15:46
    /// </remarks>
    public class ValidateDemoNUnitTest
    {

        /// <summary>
        /// Setup
        /// </summary>
        /// <remarks>
        /// <para/>Author   :  AnDequan
        /// <para/>Date     :  2021-05-18 11:23
        /// </remarks>
        [SetUp]
        public void Setup()
        {
        }

        /// <summary>
        /// 仅配置ValidateFieldAttribute使用示例 - Test
        /// </summary>
        /// <remarks>
        /// <para/>Author   :  AnDequan
        /// <para/>Date     :  2021-05-18 11:23
        /// </remarks>
        [Test]
        public void JustUseValidateFieldAttribute()
        {
            var orderNo = "ODR2021051900001";
            NoDbValidateConfig model = new NoDbValidateConfig()
            {
                OrderNo = orderNo,
                Code = "012345678901234567890123456789+1",
                NameCn = "01234567890123456789012345678901234567890123456789+1",
                NameEn = "01234567890123456789012345678901234567890123456789+1",
                Price = 15.215515M
            };
            IValidateKit validate = new ValidateKit();
            OperationResult result = validate.GetValidateResult(model, nameof(NoDbValidateConfig.OrderNo), true);
            Dictionary<object, IList<string>> errorMsg = result.Data as Dictionary<object, IList<string>>;

            Assert.IsTrue(
               (!result.Success)
                   && errorMsg.ContainsKey(orderNo)
                   && errorMsg[orderNo][0] == "系统唯一代码 maxlength is 30,the value 012345678901234567890123456789+1 invalid."
                   && errorMsg[orderNo][1] == "NameCn maxlength is 50,the value 01234567890123456789012345678901234567890123456789+1 invalid."
                   && errorMsg[orderNo][2] == "NameEn invalid."
                   && errorMsg[orderNo][3] == "Price decimal digits is 5,the value 15.215515 invalid."
               );
        }

        /// <summary>
        /// 仅配置ValidateFieldAttribute使用示例 - Test
        /// </summary>
        /// <remarks>
        /// <para/>Author   :  AnDequan
        /// <para/>Date     :  2021-05-18 11:23
        /// </remarks>
        [Test]
        public void JustUseValidateFieldAttributeList()
        {
            IList<NoDbValidateConfig> modelList = new NoDbValidateConfig[]
            {
                new NoDbValidateConfig()
                {
                    OrderNo = "ODR2021051900002",
                    Code = "012345678901234567890123456789+1",
                    NameCn = "01234567890123456789012345678901234567890123456789+1",
                    NameEn = "01234567890123456789012345678901234567890123456789+1",
                    Price = 15.215515M
                },
                new NoDbValidateConfig()
                {
                    OrderNo = "ODR2021051900003",
                    Code = "012345678901234567890123456789+1",
                    NameCn = "01234567890123456789012345678901234567890123456789+1",
                    NameEn = "01234567890123456789012345678901234567890123456789+1",
                    Price = 15.215515M
                }
            };

            IValidateKit validate = new ValidateKit();
            OperationResult result = validate.GetValidateResult(modelList, nameof(NoDbValidateConfig.OrderNo), true);
            Dictionary<object, IList<string>> errorMsg = result.Data as Dictionary<object, IList<string>>;

            Assert.IsTrue((!result.Success) && errorMsg.Count == 2);
        }
    }
}

三、配置 Database 实现校验

1. 必要表 Sys_Validate_Field 说明

在这里插入图片描述

名称类型必填长度默认值说明
Class_NamestringY255类名称,用户自定义,程序中不使用
Field_NamestringY255字段名称,用户自定义,程序中不使用
Validate_KeystringY255唯一键,全库唯一建议:类名:字段名
Validate_TypestringY255验证的数据类型或方式,不区分大小写
Regex_ExpressionstringN2000正则表达式
Regex_Expression_MsgstringN2000Regex Expression Message
RequiredboolYfalse是否必填;true:启用必填校验;false:禁用必填校验
Required_MsgstringN255类名称,用户自定义,程序中不使用
Max_LengthintN最大长度,小于等于0 则不生效此校验
Max_Length_MsgstringN2000类名称,用户自定义,程序中不使用
Decimal_Digits_LengthintY小数位数长度校验,小于等于-1则不生效此校验
Decimal_Digits_Length_MsgstringN2000类名称,用户自定义,程序中不使用
Range_StringstringN2000范围校验; 1.字符串类型的范围校验配置用 | 隔开,开头和结尾不能省略,如: |男|女| . 2. 数字类型的范围,支持Int、Long、Decimal 类型,配置示例介绍 -> 1~99 ,表示大于等于1小于等于99;1~ 表示大于等于1;~ 99 表示小于等于 99 范围校验必须指定 Validate_Type
Range_String_MsgstringNmax类名称,用户自定义,程序中不使用

2.更改了 Sys_Validate_Field表中的配置,刷新缓存

调用:  域名+ /Validation/SysValidateField/RefreshCache

提示: 当改变数据库配置之后如需立即生效,则调用.

3.查看当前生效的 Sys_Validate_Field 表的配置

调用: 域名+/Validation/SysValidateField/GetCache

4.读取Sys_Validate_Field表配置示例

4.1 实体配置信息
using Xxx.Attributes;

namespace Xxx.BI.ValidateField.NUnit.Model
{
    /// <summary>
    /// 必填测试
    /// </summary>
    /// <remarks>
    /// <para/>Author   :  AnDequan
    /// <para/>Date     :  2021-05-18 11:09
    /// </remarks>
    public class RequiredModel
    {
        /// <summary>
        /// JobNo
        /// </summary>
        [ValidateField(Required = true)]
        public string JobNo { get; set; }

        /// <summary>
        /// 年龄 
        /// </summary>
        [ValidateField(Required = true)]
        [Alias(Name = "年龄")]
        public int? Age { get; set; }//[ 1.配置了 ValidateField 特性 2.配置了别名 ] An 2021-05-18 11:14

        /// <summary>
        /// Code
        /// SQL备份:INSERT INTO Sys_Validate_Field  (  Class_Name,  Field_Name,  Validate_Key,  Validate_Type,  Regex_Expression,  Regex_Expression_Msg,  Required,  Required_Msg,  Max_Length,  Max_Length_Msg,  Decimal_Digits_Length,  Decimal_Digits_Length_Msg,  Range_String,  Range_String_Msg,  CreateUserId,  CreateUserName,  CreateTime,  Unique_No  )  VALUES  (  'Sys_Parameter',  'Code',  'Sys_Parameter:Code',  'string',  '',  '',  '1',  '{FieldName} is 必填.',  -1,  '{FieldName} maxlength is {ValidValue}.',  -1,  '{FieldName} decimal digits is {ValidValue}.',  '',  '{FieldName} valid value must in ({ValidValue}).',  'System',  'System',  'May 18 2021 10:54AM',  '4CA580EF-AC86-4299-AD3E-24A826370218'  )
        /// </summary>
        [ValidateField(Key = "Sys_Parameter:Code")]
        public string Code { get; set; }//[ 1.配置了 ValidateField 特性 走 DB的配置 ] An 2021-05-18 11:15

        /// <summary>
        /// 姓名
        /// SQL备份:INSERT INTO Sys_Validate_Field  (  Class_Name,  Field_Name,  Validate_Key,  Validate_Type,  Regex_Expression,  Regex_Expression_Msg,  Required,  Required_Msg,  Max_Length,  Max_Length_Msg,  Decimal_Digits_Length,  Decimal_Digits_Length_Msg,  Range_String,  Range_String_Msg,  CreateUserId,  CreateUserName,  CreateTime,  Unique_No  )  VALUES  (  'Sys_Parameter',  'Name_Cn',  'Sys_Parameter:Name_Cn',  'string',  '',  '',  '0',  '{FieldName} is 必填.',  -1,  '{FieldName} maxlength is {ValidValue}.',  -1,  '{FieldName} decimal digits is {ValidValue}.',  '',  '{FieldName} valid value must in ({ValidValue}).',  'System',  'System',  'May 18 2021 10:54AM',  'C1510DD7-ED27-409F-8E06-99DA81911B4D'  )
        /// 1.数据库中配置不必填 2.程序中配置必填;
        /// 最终应该没有 必填提示
        /// <para/>
        /// </summary>
        [ValidateField(Key = "Sys_Parameter:Name_Cn", Required = true)]
        public string NameCn { get; set; }

    }
}

4.2 调用结果示例如下
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using Xxx.AuxiliaryEntity;
using Xxx.BI.ValidateField.Contract;
using Xxx.BI.ValidateField.NUnit.Model;
using Xxx.BI.ValidateField.Service;
using Xxx.iW;

namespace Xxx.BI.ValidateField.NUnit
{
    /// <summary>
    /// 必填项测试
    /// </summary>
    /// <remarks>
    /// <para/>Author   :  AnDequan
    /// <para/>Date     :  2021-05-18 10:30
    /// </remarks>
    public class ValidateNUnitTest
    {

        /// <summary>
        /// 验证服务
        /// </summary>
        IValidationService ValidateService { get; set; }

        /// <summary>
        /// Setup
        /// </summary>
        /// <remarks>
        /// <para/>Author   :  AnDequan
        /// <para/>Date     :  2021-05-18 11:23
        /// </remarks>
        [SetUp]
        public void Setup()
        {
            IRepository _Repository; _Repository = new Repository<SqlConnection>("换成自己的连接字符串");
            ValidateService = new ValidationService(_Repository);
        }

        /// <summary>
        /// 必填校验
        /// </summary>
        /// <remarks>
        /// <para/>Author   :  AnDequan
        /// <para/>Date     :  2021-05-18 11:23
        /// </remarks>
        [Test]
        public void Required()
        {
            var jobNo = "R000001";
            RequiredModel model = new RequiredModel() { JobNo = jobNo, };
            IValidateKit validate = new ValidateKit(ValidateService);
            OperationResult result = validate.GetValidateResult(model, nameof(RequiredModel.JobNo), true);
            Dictionary<object, IList<string>> errorMsg = result.Data as Dictionary<object, IList<string>>;

            Assert.IsTrue(
               (!result.Success)
                   && errorMsg.ContainsKey(jobNo)
                   && errorMsg[jobNo][0] == "年龄 is required."
                   && errorMsg[jobNo][1] == "Code is 必填."
               );
        }
    }
}

附录

更多详细的单元测试信息 请查看 Xxx.BI.Validate 项目中 Xxx.BI.Validate.NUnit 里边详细的单元测试.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安得权

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值