自定义一个简单的数据模型验证器类,可用于各类验证场景,待后续完善

如题,自定义一个简单的数据模型验证器类(ModelValidator),目前只有提供基本的手动调用验证方法进行验证,并最终输出验证结果,待后续完善,增加基于特性的自动验证并输出验证结果的功能,代码实现比较简单,直接贴出源代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace Zuowj.Common
{
    /// <summary>
    /// 模型验证器类(用于验证实体类的相关属性是否符合验证规则)
    /// Author:zuowenjun
    /// Date:2018-5-25
    /// </summary>
    public class ModelValidator
    {
        private StringBuilder errorMsgBuilder = new StringBuilder();
        private bool isValid = true;
        public bool IsValid
        {
            get { return isValid; }
        }


        public bool IsNotNullOrWhiteSpace(string str, string fieldName)
        {
            bool result = string.IsNullOrWhiteSpace(str);
            if (result)
            {
                errorMsgBuilder.AppendFormat("{0}不能为空;{1}", fieldName, Environment.NewLine);
                isValid = false;
            }

            return result;
        }

        public bool IsNumeric(string numStr, string fieldName)
        {
            decimal numValue;
            bool result = decimal.TryParse(numStr, out numValue);
            if (!result)
            {
                errorMsgBuilder.AppendFormat("{0}不是数字;{1}", fieldName, Environment.NewLine);
                isValid = false;
            }

            return result;
        }

        public bool IsDateTime(string timeStr, string fieldName)
        { 
            DateTime time;
            bool result = DateTime.TryParse(timeStr, out time);
            if(!result)
            {
                errorMsgBuilder.AppendFormat("{0}不是日期;{1}", fieldName, Environment.NewLine);
                isValid = false;
            }
            return result;
        }

        public bool IsGreaterThan<T>(T fieldValue, T compareValue, bool allowEqual, string fieldName) where T : IComparable
        {
            int compResult = fieldValue.CompareTo(compareValue);
            bool result = false;
            if (compResult > 0 || (allowEqual && compResult >= 0))
            {
                result = true;
            }
            else
            {
                errorMsgBuilder.AppendFormat("{0}必需{1}{2};{3}", fieldName, allowEqual ? "大于或等于" : "大于", compareValue, Environment.NewLine);
                result = false;
                isValid = false;
            }

            return result;
        }

        public bool IsLessThan<T>(T fieldValue, T compareValue, bool allowEqual, string fieldName) where T : IComparable
        {
            int compResult = fieldValue.CompareTo(compareValue);
            bool result = false;
            if (compResult < 0 || (allowEqual && compResult <= 0))
            {
                result = true;
            }
            else
            {
                errorMsgBuilder.AppendFormat("{0}必需{1}{2};{3}", fieldName, allowEqual ? "小于或等于" : "小于", compareValue, Environment.NewLine);
                result = false;
                isValid = false;
            }

            return result;
        }


        public bool HasItem<T>(IEnumerable<T> list, string fieldName)
        {
            bool result = true;
            if (list == null || !list.Any())
            {
                result = false;
                errorMsgBuilder.AppendFormat("{0}没有任何集合;{1}", fieldName, Environment.NewLine);
                isValid = false;
            }

            return result;
        }

        public bool CustomValidate<T>(T fieldValue, Func<T, string> validateFunc)
        {
            string errorMsg = validateFunc(fieldValue);
            if (!string.IsNullOrWhiteSpace(errorMsg))
            {
                return AppendErrorMessage(errorMsg);
            }
            else
            {
                return true;
            }
        }

        public bool AppendErrorMessage(string errorMsg)
        {
            errorMsgBuilder.AppendLine(errorMsg);
            isValid = false;
            return false;
        }

        public string GetErrorMessage()
        {
            return errorMsgBuilder.ToString();
        }

        public override string ToString()
        {
            return errorMsgBuilder.ToString();
        }


    }
}

 从代码可以看出,基本上只是提供了一些常见的逻辑验证方法而矣,并把验证的结果返回,同时组合验证的错误结果信息,以便最终可以输出完整的验证失败的信息。

用法很简单,new一个ModelValidator,然后根据自己的MODEL验证规则,调用对应的验证方法,最终输出验证结果即可,如下示例:

//BLL层:(验证调用入口)
                var validateResult = CheckFreightChargeReqDto(requestDto, tranType);
                if (!validateResult.IsValid)
                {
                    throw new Exception(validateResult.GetErrorMessage());
                }




//具体的验证逻辑:(自定义封装的验证方法,取决于个人)
        private ModelValidator CheckFreightChargeReqDto(FreightChargeReqDto requestDto, FreightChargeTranType tranType)
        {
            ModelValidator validator = new ModelValidator();
            if (tranType == FreightChargeTranType.Calculate)
            {
                validator.IsNotNullOrWhiteSpace(requestDto.CustomerName, "客户名称");
            }
            validator.IsNotNullOrWhiteSpace(requestDto.ServiceType, "服务方式");
            validator.IsNotNullOrWhiteSpace(requestDto.FromZoneNo, "始发区号");
            validator.IsNotNullOrWhiteSpace(requestDto.ToZoneNo, "目的区号");
            validator.IsNotNullOrWhiteSpace(requestDto.ProjectNo, "项目编号");
            if (validator.HasItem(requestDto.SpecQueryItems, "规格查询列表"))
            {
                if (requestDto.SpecQueryItems.Any(t => string.IsNullOrWhiteSpace(t.SpecNo)))
                {
                    validator.AppendErrorMessage("规格编号不能为空;");
                }

                if (requestDto.SpecQueryItems.Any(t => string.IsNullOrEmpty(t.SpecName) && string.IsNullOrEmpty(t.SpecNo)))
                {
                    validator.AppendErrorMessage("规格编号、规格名称两者必需有1个不能为空;");
                }
                else
                {

                    var specQueryItemWithSpecNos = requestDto.SpecQueryItems.Where(t => !string.IsNullOrEmpty(t.SpecNo));
                    if (specQueryItemWithSpecNos.Count() > specQueryItemWithSpecNos.Select(t => t.SpecNo).Distinct().Count())
                    {
                        validator.AppendErrorMessage("规格编号存在重复;");
                    }

                    var specQueryItemWithSpecNames = requestDto.SpecQueryItems.Where(t => !string.IsNullOrEmpty(t.SpecName) && string.IsNullOrEmpty(t.SpecNo));
                    if (specQueryItemWithSpecNames.Count() > specQueryItemWithSpecNames.Select(t => t.SpecName).Distinct().Count())
                    {
                        validator.AppendErrorMessage("规格名称存在重复;");
                    }

                }

                if (validator.IsValid)
                {
                    validator.IsLessThan(requestDto.SpecQueryItems.Count, 20, true, "规格批量查询数");
                }
            }


            return validator;
        }



    public class FreightChargeReqDto
    {
        public int TranType { get; set; }
        public string CustomerName { get; set; }
        public string ServiceType { get; set; }
        public string FromZoneNo { get; set; }
        public string ToZoneNo { get; set; }
        public string ProjectNo { get; set; }

        public List<ECProjectSpecQueryItem> SpecQueryItems { get; set; }

        public class ECProjectSpecQueryItem
        {
            public string SpecNo { get; set; }
            public string SpecName { get; set; }
            public int PCS { get; set; }
            public double Weight { get; set; }
            public double CubicQty { get; set; }
        }
    }

由于使用简单且功能还有待进一步完善,故在此就不再详细说明,后续若完善了再补充说明吧。

如果是ASP.NET MVC 或 ASP.NET CORE 建议可以参考我之前的文章:《ASP.NET MVC必知必会知识点总结(二)》 文末总结的几种对于MVC的模型验证的方法;

另外推荐一个已有的验证组件:FluentValidation,这个类似于我本文实现的效果,但人家做得比较完善,将每个验证的逻辑变成一个个自定义的验证Rule集合,大家有兴趣的可以看一下:https://github.com/JeremySkinner/FluentValidation

posted @ 2019-01-29 13:13  梦在旅途  阅读(721)  评论(0编辑  收藏  举报