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