最佳实践_C#Api对接实体校验

工作之后,做过不少的api对接,有提供api接口,也有调用对方api接口。api对接中,实体校验一定是必不可少的一个通用模块。

正常情况下,实体校验通常包括:a 是否必填;b 数据类型;c 最大长度;d 取值范围;e 集合最大数量。

这里记录下自己的最佳实践,并作简单解释。

  1  public class DataValidateHelper
  2     {
  3         public static List<DataValidateResult> Validate<T>(T model)
  4         {
  5             var result = new List<DataValidateResult>();
  6             var properties = model.GetType().GetProperties();
  7             foreach (var item in properties)
  8             {
  9                 var ats = item.GetCustomAttribute(typeof(DataValidateAttribute), true) as DataValidateAttribute;
 10                 if (ats == null)
 11                     continue;
 12 
 13                 if (item.PropertyType.Equals(typeof(string)))
 14                 {
 15                     var v = Convert.ToString(item.GetValue(model));
 16                     if (ats.Required && string.IsNullOrEmpty(v))
 17                     {
 18                         result.Add(new DataValidateResult(item.Name, v, ats.Message));
 19                         continue;
 20                     }
 21 
 22                     if (!ats.Required && string.IsNullOrEmpty(v))
 23                         continue;
 24 
 25                     if (ats.RegexString == null)
 26                         continue;
 27                     var regex = new Regex(ats.RegexString);
 28                     if (regex.IsMatch(v))
 29                         continue;
 30 
 31                     result.Add(new DataValidateResult(item.Name, v, ats.Message));
 32                     continue;
 33                 }
 34 
 35                 if (item.PropertyType.Equals(typeof(List<string>)))
 36                 {
 37                     var v = (List<string>)item.GetValue(model);
 38                     if (ats.Required && (v == null || v.Count == 0))
 39                     {
 40                         result.Add(new DataValidateResult(item.Name, "null", ats.Message));
 41                         continue;
 42                     }
 43 
 44                     if (!ats.Required && (v == null || v.Count == 0))
 45                         continue;
 46 
 47                     if (ats.MaxListCount > 0 && ats.MaxListCount < v.Count)
 48                     {
 49                         result.Add(new DataValidateResult(item.Name, v.Count.ToString(), ats.Message));
 50                         continue;
 51                     }
 52 
 53                     if (ats.RegexString == null)
 54                         continue;
 55                     foreach (var children in v)
 56                     {
 57                         var regex = new Regex(ats.RegexString);
 58                         if (regex.IsMatch(children))
 59                             continue;
 60 
 61                         result.Add(new DataValidateResult(item.Name, children, ats.Message));
 62                     }
 63                     continue;
 64                 }
 65 
 66                 if (item.PropertyType.IsClass)
 67                 {
 68                     if (item.PropertyType.IsGenericType)
 69                     {
 70                         var v = item.GetValue(model) as IEnumerable<object>;
 71                         if (ats.Required && (v == null || v.Count() == 0))
 72                         {
 73                             result.Add(new DataValidateResult(item.Name, "null", ats.Message));
 74                             continue;
 75                         }
 76 
 77                         if (!ats.Required && (v == null || v.Count() == 0))
 78                             continue;
 79 
 80                         if (ats.MaxListCount > 0 && ats.MaxListCount < v.Count())
 81                         {
 82                             result.Add(new DataValidateResult(item.Name, v.Count().ToString(), ats.Message));
 83                             continue;
 84                         }
 85 
 86                         foreach (var children in v)
 87                         {
 88                             result.AddRange(Validate(children));
 89                         }
 90                         continue;
 91                     }
 92 
 93                     var va = item.GetValue(model);
 94                     if (ats.Required && va == null)
 95                     {
 96                         result.Add(new DataValidateResult(item.Name, "null", ats.Message));
 97                         continue;
 98                     }
 99 
100                     if (!ats.Required && va == null)
101                         continue;
102 
103                     result.AddRange(Validate(va));
104                 }
105             }
106 
107             return result;
108         }
109     }
110 
111     public class DataValidateResult
112     {
113         public string CoulumnName { get; set; }
114         public string CoulumnValue { get; set; }
115         public string ErroMessage { get; set; }
116 
117         public DataValidateResult(string columnName, string coulumnValue, string erroMessage)
118         {
119             CoulumnName = columnName;
120             CoulumnValue = coulumnValue;
121             ErroMessage = erroMessage;
122         }
123     }
124 
125     public class DataValidateAttribute : Attribute
126     {
127         public bool Required { get; set; }
128         public string RegexString { get; set; }
129         public int MaxListCount { get; set; }
130         public string Message { get; set; }
131     }
View Code

简单解释下

1 实体内字段数据类型共4中:string类型;List<string>类型;T类型;List<T>类型。最小颗粒度当然就是string,避免一些默认值不是null的数据类型,因默认值引起的实际值变化。

2 通过字段特性设置校验,Required:是否必填;MaxListCount:集合最大数量;RegexString:其余校验通过正则表达式体现;Message:自定义校验失败提示。

3 字段校验结果List<DataValidateResult>,所有校验失败的信息在该集合内体现,字段名/当前值/失败提示信息。至于api怎么展现和使用这些校验结果,根绝返回结果自己拼装。

4 整个校验逻辑的主题思想是:通过反射和递归出作为最小颗粒度的每个字段,并将其值和通过特性设置的限制条件对比,如果不符合则视为校验失败,并返回失败信息。

posted @ 2022-03-23 22:54  西瓜凳  阅读(416)  评论(0编辑  收藏  举报