• 数据验证随想(续)


    梳理需求

      关于这个想法,想看看历史背景的,请移步 《数据验证随想》

      今天要说的是这个组件在项目中的应用,以及后期对它的改善。在原来的想法中,希望做的大而全,结果越往后做,发现有点过度设计,写完代码后,楼主自己都懒得用。与其这么麻烦,还不如直接几个 if 判断完事。

      既然如此,只能将问题简单化。认真梳理一下楼主的需求:

      1. 部分参数是必需的,验证失败,中断,并返回该错误信息。

      2. 部分参数是非必需的。验证失败就直接忽略。这个需求来自于,表单里部分值是可以空的,或者传递了意外的值,试图忽略它。

      3. 验证成功后的参数,最好是能直接使用,而且类型都是转换后的。

    解决方案

      先看看代码上是怎么调用的。

                var v = ValidateHelp.BeginEntity<PumpCodeEntity>()
                    .IsNullOrEmpty(form["tybh"], "统一编号", "未找到需要修改的数据")
                    .IsInt(form["zldm"], "指令代码", "指令代码错误")
                    .IsInt(form["sfyx"], "是否有效", "有效指令错误");
                if (v.IsInValid) //数据无效
                {
                    return new ResultDTO() { Message = v.Message};
                }
                ......

      其中form是MVC的FormCollection对象,没用过的理解成HttpRequest也成。

      PumpCodeEntity 是实体对象,呃,其中 “统一编号、指令代码、是否有效” 是这个对象的属性。为什么它会是中文,这个有项目背景,重点不是它啦。

      大家可以看到,其中有3个验证方法,方法带有3个参数,分别是:

      待验证的值 

      Key名或属性名(验证成功存储在Dictionary中, 或通过反射存储在对象中)

      错误消息提示  当未传递错误信息参数时,表示当前验证的参数是非必需的。由于在验证参数时,尝试对参数做了类型转换,故验证成功后,参数的类型是正确的,将参数存储到Dictionary<string,object>中,或者是对象的属性中。

      因此增加检测条件时,只需要增加一个类型的判断方法即可。代码中已经内置了检测整数、浮点数、双精度、时间、正则等。

      详细代码如下:

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 using System.Text;
      5 using System.Text.RegularExpressions;
      6 using CheckHandle = System.Func<Core.Data.ValidateHelp, string, string, string, Core.Data.ValidateHelp>;
      7 namespace Core.Data
      8 {
      9     public class ValidateHelp
     10     {
     11         #region 属性
     12         //数据容器字典
     13         public Dictionary<string, object> Data { get; protected set; }
     14         //数据容器实体
     15         public Object Entity { get; protected set; }
     16         //错误信息
     17         public string Message { get; protected set; }
     18         /// <summary>
     19         /// true:数据无效 false:数据有效
     20         /// </summary>
     21         private bool isInValid;
     22         /// <summary>
     23         /// true:数据无效 false:数据有效
     24         /// </summary>
     25         public bool IsInValid { get { return isInValid; } }
     26         #endregion
     27 
     28         #region 字段
     29 
     30         //数据容器实体类型
     31         protected Type EntityType;
     32         //验证委托缓存
     33         private static Dictionary<string, CheckHandle> checkHandlers = new Dictionary<string, CheckHandle>();
     34 
     35         #endregion
     36 
     37         #region 静态方法 得到对象实例
     38         public static ValidateHelp Begin()
     39         {
     40             var v = new ValidateHelp();
     41             v.Data = new Dictionary<string, object>();
     42             return v;
     43         }
     44 
     45         public static ValidateHelp BeginEntity<T>()
     46         {
     47             var v = new ValidateHelp();
     48             v.EntityType = typeof(T);
     49             v.Entity = Activator.CreateInstance(v.EntityType);
     50             return v;
     51         }
     52         #endregion
     53 
     54         #region 私有辅助方法
     55         private ValidateHelp()
     56         {
     57         }
     58 
     59 
     60         private static ValidateHelp Error(ValidateHelp v, string msg)
     61         {
     62             //没有错误信息 默认不修改验证结果
     63             if (msg == null || msg.Length == 0)
     64             {
     65                 return v;
     66             }
     67             v.isInValid = true;
     68             v.Message = msg;
     69             return v;
     70         }
     71 
     72         private static ValidateHelp Success(ValidateHelp v, object value, string propertyName)
     73         {
     74             if (v.IsInValid) return v;
     75             if (propertyName != null && propertyName.Length > 0)
     76             {
     77                 if (v.Data != null)
     78                 {
     79                     v.Data[propertyName] = value;
     80                 }
     81                 else if (v.Entity != v)
     82                 {
     83                     var p = v.Entity.GetType().GetProperty(propertyName);
     84                     //为对象属性赋值
     85                     p.SetValue(v.Entity, value, null);
     86                 }
     87             }
     88             return v;
     89         }
     90 
     91         private ValidateHelp Check(string[] args, CheckHandle fun)
     92         {
     93             if (args == null || args.Length == 0 || args.Length > 3)
     94             {
     95                 throw new Exception("验证参数错误");
     96             }
     97             //如果之前验证失败,就直接返回
     98             if (isInValid) return this;
     99             var value = args[0];
    100             var propertyName = args.Length > 1 ? args[1] : null;
    101             var msg = args.Length > 2 ? args[2] : null;
    102             return fun(this, value, propertyName, msg);
    103         }
    104 
    105         #endregion
    106 
    107         #region 公有辅助方法
    108         public object this[string key]
    109         {
    110             get
    111             {
    112                 object o;
    113                 if (Data.TryGetValue(key, out o)) return o;
    114                 return null;
    115             }
    116         }
    117         #endregion
    118 
    119         #region 验证方法
    120         public virtual ValidateHelp IsNullOrEmpty(params string[] args)
    121         {
    122             CheckHandle handler;
    123             if (!checkHandlers.TryGetValue("IsNullOrEmpty", out handler))
    124             {
    125                 handler = (scope, s, p, m) =>
    126                 {
    127                     if (s == null || s.Length == 0)
    128                     {
    129                         return Error(scope, m);
    130                     }
    131                     return Success(scope, s, p);
    132                 };
    133                 checkHandlers["IsNullOrEmpty"] = handler;
    134             };
    135             return Check(args, handler);
    136         }
    137         public virtual ValidateHelp IsInt(params string[] args)
    138         {
    139             CheckHandle handler;
    140             if (!checkHandlers.TryGetValue("IsInt", out handler))
    141             {
    142                 handler = (scope, s, p, m) =>
    143                 {
    144                     int i;
    145                     if (!int.TryParse(s, out i))
    146                     {
    147                         return Error(scope, m);
    148                     }
    149                     return Success(scope, i, p);
    150                 };
    151                 checkHandlers["IsInt"] = handler;
    152             };
    153             return Check(args, handler);
    154         }
    155 
    156         public virtual ValidateHelp IsDouble(params string[] args)
    157         {
    158             CheckHandle handler;
    159             if (!checkHandlers.TryGetValue("IsDouble", out handler))
    160             {
    161                 handler = (scope, s, p, m) =>
    162                 {
    163                     double i;
    164                     if (!double.TryParse(s, out i))
    165                     {
    166                         return Error(scope, m);
    167                     }
    168                     return Success(scope, i, p);
    169                 };
    170                 checkHandlers["IsDouble"] = handler;
    171             };
    172             return Check(args, handler);
    173         }
    174 
    175         public virtual ValidateHelp IsLong(params string[] args)
    176         {
    177             CheckHandle handler;
    178             if (!checkHandlers.TryGetValue("IsLong", out handler))
    179             {
    180                 handler = (scope, s, p, m) =>
    181                 {
    182                     long i;
    183                     if (!long.TryParse(s, out i))
    184                     {
    185                         return Error(scope, m);
    186                     }
    187                     return Success(scope, i, p);
    188                 };
    189                 checkHandlers["IsLong"] = handler;
    190             };
    191             return Check(args, handler);
    192         }
    193 
    194         public virtual ValidateHelp IsFloat(params string[] args)
    195         {
    196             CheckHandle handler;
    197             if (!checkHandlers.TryGetValue("IsFloat", out handler))
    198             {
    199                 handler = (scope, s, p, m) =>
    200                 {
    201                     float i;
    202                     if (!float.TryParse(s, out i))
    203                     {
    204                         return Error(scope, m);
    205                     }
    206                     return Success(scope, i, p);
    207                 };
    208                 checkHandlers["IsFloat"] = handler;
    209             };
    210             return Check(args, handler);
    211         }
    212 
    213         public virtual ValidateHelp IsBool(params string[] args)
    214         {
    215             CheckHandle handler;
    216             if (!checkHandlers.TryGetValue("IsBool", out handler))
    217             {
    218                 handler = (scope, s, p, m) =>
    219                 {
    220                     bool i;
    221                     if (!bool.TryParse(s, out i))
    222                     {
    223                         return Error(scope, m);
    224                     }
    225                     return Success(scope, i, p);
    226                 };
    227                 checkHandlers["IsBool"] = handler;
    228             };
    229             return Check(args, handler);
    230         }
    231 
    232         public virtual ValidateHelp IsDateTime(params string[] args)
    233         {
    234             CheckHandle handler;
    235             if (!checkHandlers.TryGetValue("IsDateTime", out handler))
    236             {
    237                 handler = (scope, s, p, m) =>
    238                 {
    239                     DateTime i;
    240                     if (!DateTime.TryParse(s, out i))
    241                     {
    242                         return Error(scope, m);
    243                     }
    244                     return Success(scope, i, p);
    245                 };
    246                 checkHandlers["IsDateTime"] = handler;
    247             };
    248             return Check(args, handler);
    249         }
    250 
    251         public virtual ValidateHelp IsEnum<T>(params string[] args) where T : struct
    252         {
    253             CheckHandle handler;
    254             if (!checkHandlers.TryGetValue("IsEnum", out handler))
    255             {
    256                 handler = (scope, s, p, m) =>
    257                 {
    258                     T i;
    259                     if (!Enum.TryParse(s, true, out i))
    260                     {
    261                         return Error(scope, m);
    262                     }
    263                     return Success(scope, i, p);
    264                 };
    265                 checkHandlers["IsEnum"] = handler;
    266             };
    267             return Check(args, handler);
    268         }
    269 
    270         public virtual ValidateHelp IsRegex(string pattern, params string[] args)
    271         {
    272             CheckHandle handler;
    273             if (!checkHandlers.TryGetValue(pattern, out handler))
    274             {
    275                 handler = (scope, s, p, m) =>
    276                 {
    277                     if (!Regex.IsMatch(s, pattern))
    278                     {
    279                         return Error(scope, m);
    280                     }
    281                     return Success(scope, s, p);
    282                 };
    283                 checkHandlers[pattern] = handler;
    284             };
    285             return Check(args, handler);
    286         }
    287 
    288         public virtual ValidateHelp IsChar(params string[] args)
    289         {
    290             return IsRegex(@"^[A-Za-z]+$", args);
    291         }
    292 
    293         public virtual ValidateHelp IsNumber(params string[] args)
    294         {
    295             return IsRegex(@"^d+$", args);
    296         }
    297 
    298         public virtual ValidateHelp IsChinese(params string[] args)
    299         {
    300             return IsRegex(@"^[u4e00-u9fa5]+$", args);
    301         }
    302 
    303         public virtual ValidateHelp IsEmail(params string[] args)
    304         {
    305             return IsRegex(@"^[w-]+(.[w-]+)*@[w-]+(.[w-]+)+$", args);
    306         }
    307 
    308         public virtual ValidateHelp IsIP(params string[] args)
    309         {
    310             return IsRegex(@"^((2[0-4]d|25[0-5]|[01]?dd?).){3}(2[0-4]d|25[0-5]|[01]?dd?)$", args);
    311         }
    312 
    313         public virtual ValidateHelp IsUrl(params string[] args)
    314         {
    315             return IsRegex(@"^([a-zA-z]+://)?(w+(-w+)*)(.(w+(-w+)*))*(?S*)?$", args);
    316         }
    317 
    318         public virtual ValidateHelp IsPhone(params string[] args)
    319         {
    320             return IsRegex(@"((d{11})|^((d{7,8})|(d{4}|d{3})-(d{7,8})|(d{4}|d{3})-(d{7,8})-(d{4}|d{3}|d{2}|d{1})|(d{7,8})-(d{4}|d{3}|d{2}|d{1}))$)", args);
    321         }
    322         #endregion
    323     }
    324 }
    ValidateHelp.cs

      其中验证方法使用了委托,用字典缓存委托。

    最后

      有个问题,一直找不到好的方式解决,比如验证了10个参数,第1个的时候就验证失败,除了抛出异常,楼主暂时想不到什么方法可以中断后面的验证,但是抛异常带来的代码量非常大,因此折衷方案是,在具体的验证逻辑中,若已经验证失败,则直接跳过。

      将属性值赋值到实体上,使用的方式是反射,这一块可以优化一下,可以看看  《[源码]Literacy 快速反射读写对象属性,字段》 。使用反射的时候,属性名是大小写敏感的,而这个Literacy是可以设置大小写不敏感。

      示例项目是临时写的,验证代码在Default.aspx.cs里。

      示例下载

      

  • 相关阅读:
    关于postman使用上发现的一点问题
    关于异步的处理方法
    关于console.log() 打印得引用类型得数据得相关问题
    使用electron将单页面vue webapp 打包成 PC端应用
    当后台只接受字符串得时候,在传输复杂得数据得时候会发生得问题
    默认事件
    事件冒泡
    offsetWidth clientWidth scrollWidth 三者之间的区别和联系
    事件获取目标 currentTarget target srcElement三者之间的区别和联系
    不支持模块化规范的插件可以使用import 导入的原因
  • 原文地址:https://www.cnblogs.com/codealone/p/3798408.html
Copyright © 2020-2023  润新知