如题,自定义一个简单的数据模型验证器类(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