使用 Fluent 验证的 Model T 的通用验证器?
Generic Validator for Model T Using Fluent Validation?
我昨天刚接触 Fluent Validation,我觉得它很酷。我已经尝试过了并且有效。但是我的应用程序目前有多个模型,我必须承认为每个模型编写验证器压力很大。是否可以用泛型编写并找到一种方法来验证每个模型?
我的验证器目前就是这样写的。但是不知道泛型怎么写
EmployeeValidator.cs
public class EmployeeValidator : AbstractValidator<EmployeeViewModel>
{
private readonly ValidationEntitySettingServices _validationEntitySettingService;
public EmployeeValidator(ValidationEntitySettingServices validationEntitySettingService)
{
_validationEntitySettingService = validationEntitySettingService;
RuleFor(x => x.LastName).NotEmpty().When(x => IsPropertyRequired(x.LastName)).WithMessage("Last Name is a required field!");
RuleFor(x => x.FirstName).NotEmpty().When(x => IsPropertyRequired(x.FirstName)).WithMessage("First Name is a required field!");
RuleFor(x => x.MiddleName).NotEmpty().When(x => IsPropertyRequired(x.MiddleName)).WithMessage("Middle Name is a required field!");
}
public bool IsPropertyRequired(string propertyName)
{
var empValidationSetting = _validationEntitySettingService.GetIncluding("Employee");
if (empValidationSetting != null)
{
return empValidationSetting.ValidationEntityProperties.Any(p => p.PropertyName.Equals(propertyName) && p.IsRequired);
}
else
return false;
}
}
提前致谢。
我认为使验证通用化没有任何意义,因为您的所有模型可能具有不同的属性和 属性 类型,需要以不同的方式进行验证。但是,您可以通过添加基本验证 class 使您在这里拥有的内容更通用,例如:
public abstract class BaseValidator<T> : AbstractValidator<T>
{
private readonly ValidationEntitySettingServices _validationEntitySettingService;
public BaseValidator(ValidationEntitySettingServices validationEntitySettingService)
{
_validationEntitySettingService = validationEntitySettingService;
AutoApplyEmptyRules();
}
private string ViewModelName
{
get { return GetType().Name.Replace("Validator", string.Empty); }
}
// no longer needed
//public bool IsPropertyRequired(string propertyName)
//{
// var validationSetting = _validationEntitySettingService.GetIncluding(ViewModelName);
// if (validationSetting != null)
// {
// return validationSetting.ValidationEntityProperties.Any(p => p.PropertyName.Equals(propertyName) && p.IsRequired);
// }
// else
// return false;
//}
protected void AddEmptyRuleFor<TProperty>(Expression<Func<T, TProperty>> expression, string message)
{
//RuleFor(expression).NotEmpty().When(x => IsPropertyRequired(((MemberExpression)expression.Body).Name)).WithMessage(message);
RuleFor(expression).NotEmpty().WithMessage(message);
}
private void AddEmptyRuleForProperty(PropertyInfo property)
{
MethodInfo methodInfo = GetType().GetMethod("AddEmptyRuleFor");
Type[] argumentTypes = new Type[] { typeof(T), property.PropertyType };
MethodInfo genericMethod = methodInfo.MakeGenericMethod(argumentTypes);
object propertyExpression = ExpressionHelper.CreateMemberExpressionForProperty<T>(property);
genericMethod.Invoke(this, new object[] { propertyExpression, $"{propertyInfo.Name} is a required field!" });
}
private PropertyInfo[] GetRequiredProperties()
{
var validationSetting = _validationEntitySettingService.GetIncluding(ViewModelName);
if (validationSetting != null)
{
return validationSetting.ValidationEntityProperties.Where(p => p.IsRequired);
}
else
return null;
}
private void AutoApplyEmptyRules()
{
PropertyInfo[] properties = GetRequiredProperties();
if (properties == null)
return;
foreach (PropertyInfo propertyInfo in properties)
{
AddEmptyRuleForProperty(property);
}
}
}
此处的主要要求是 AddEmptyRuleForProperty 方法,它将通过基于 PropertyType 构造方法来调用通用 AddEmptyRuleFor 方法。
然后您可以继承此 class 并使用通用方法应用规则:
public class EmployeeValidator : BaseValidator<EmployeeViewModel>
{
public EmployeeValidator(ValidationEntitySettingServices validationEntitySettingService) : base(validationEntitySettingService)
{
// no longer needed
//AddEmptyRuleFor(x => x.LastName, "Last Name is a required field!");
//AddEmptyRuleFor(x => x.FirstName, "First Name is a required field!");
//AddEmptyRuleFor(x => x.MiddleName, "Middle Name is a required field!");
}
}
这是 ExpressionHelper class,它提供了一种创建通用成员表达式作为对象的方法,可以在调用上面的 AddEmptyRuleFor 方法时传入该对象:
public static class ExpressionHelper
{
public static Expression<Func<TModel, TProperty>> CreateMemberExpression<TModel, TProperty>(PropertyInfo propertyInfo)
{
if (propertyInfo == null)
throw new ArgumentException("Argument cannot be null", "propertyInfo");
ParameterExpression entityParam = Expression.Parameter(typeof(TModel), "x");
Expression columnExpr = Expression.Property(entityParam, propertyInfo);
if (propertyInfo.PropertyType != typeof(T))
columnExpr = Expression.Convert(columnExpr, typeof(T));
return Expression.Lambda<Func<TModel, TProperty>>(columnExpr, entityParam);
}
public static object CreateMemberExpressionForProperty<TModel>(PropertyInfo property)
{
MethodInfo methodInfo = typeof(ExpressionHelper).GetMethod("CreateMemberExpression", BindingFlags.Static | BindingFlags.Public);
Type[] argumentTypes = new Type[] { typeof(TModel), property.PropertyType };
MethodInfo genericMethod = methodInfo.MakeGenericMethod(argumentTypes);
return genericMethod.Invoke(null, new object[] { property });
}
}
我昨天刚接触 Fluent Validation,我觉得它很酷。我已经尝试过了并且有效。但是我的应用程序目前有多个模型,我必须承认为每个模型编写验证器压力很大。是否可以用泛型编写并找到一种方法来验证每个模型?
我的验证器目前就是这样写的。但是不知道泛型怎么写
EmployeeValidator.cs
public class EmployeeValidator : AbstractValidator<EmployeeViewModel>
{
private readonly ValidationEntitySettingServices _validationEntitySettingService;
public EmployeeValidator(ValidationEntitySettingServices validationEntitySettingService)
{
_validationEntitySettingService = validationEntitySettingService;
RuleFor(x => x.LastName).NotEmpty().When(x => IsPropertyRequired(x.LastName)).WithMessage("Last Name is a required field!");
RuleFor(x => x.FirstName).NotEmpty().When(x => IsPropertyRequired(x.FirstName)).WithMessage("First Name is a required field!");
RuleFor(x => x.MiddleName).NotEmpty().When(x => IsPropertyRequired(x.MiddleName)).WithMessage("Middle Name is a required field!");
}
public bool IsPropertyRequired(string propertyName)
{
var empValidationSetting = _validationEntitySettingService.GetIncluding("Employee");
if (empValidationSetting != null)
{
return empValidationSetting.ValidationEntityProperties.Any(p => p.PropertyName.Equals(propertyName) && p.IsRequired);
}
else
return false;
}
}
提前致谢。
我认为使验证通用化没有任何意义,因为您的所有模型可能具有不同的属性和 属性 类型,需要以不同的方式进行验证。但是,您可以通过添加基本验证 class 使您在这里拥有的内容更通用,例如:
public abstract class BaseValidator<T> : AbstractValidator<T>
{
private readonly ValidationEntitySettingServices _validationEntitySettingService;
public BaseValidator(ValidationEntitySettingServices validationEntitySettingService)
{
_validationEntitySettingService = validationEntitySettingService;
AutoApplyEmptyRules();
}
private string ViewModelName
{
get { return GetType().Name.Replace("Validator", string.Empty); }
}
// no longer needed
//public bool IsPropertyRequired(string propertyName)
//{
// var validationSetting = _validationEntitySettingService.GetIncluding(ViewModelName);
// if (validationSetting != null)
// {
// return validationSetting.ValidationEntityProperties.Any(p => p.PropertyName.Equals(propertyName) && p.IsRequired);
// }
// else
// return false;
//}
protected void AddEmptyRuleFor<TProperty>(Expression<Func<T, TProperty>> expression, string message)
{
//RuleFor(expression).NotEmpty().When(x => IsPropertyRequired(((MemberExpression)expression.Body).Name)).WithMessage(message);
RuleFor(expression).NotEmpty().WithMessage(message);
}
private void AddEmptyRuleForProperty(PropertyInfo property)
{
MethodInfo methodInfo = GetType().GetMethod("AddEmptyRuleFor");
Type[] argumentTypes = new Type[] { typeof(T), property.PropertyType };
MethodInfo genericMethod = methodInfo.MakeGenericMethod(argumentTypes);
object propertyExpression = ExpressionHelper.CreateMemberExpressionForProperty<T>(property);
genericMethod.Invoke(this, new object[] { propertyExpression, $"{propertyInfo.Name} is a required field!" });
}
private PropertyInfo[] GetRequiredProperties()
{
var validationSetting = _validationEntitySettingService.GetIncluding(ViewModelName);
if (validationSetting != null)
{
return validationSetting.ValidationEntityProperties.Where(p => p.IsRequired);
}
else
return null;
}
private void AutoApplyEmptyRules()
{
PropertyInfo[] properties = GetRequiredProperties();
if (properties == null)
return;
foreach (PropertyInfo propertyInfo in properties)
{
AddEmptyRuleForProperty(property);
}
}
}
此处的主要要求是 AddEmptyRuleForProperty 方法,它将通过基于 PropertyType 构造方法来调用通用 AddEmptyRuleFor 方法。
然后您可以继承此 class 并使用通用方法应用规则:
public class EmployeeValidator : BaseValidator<EmployeeViewModel>
{
public EmployeeValidator(ValidationEntitySettingServices validationEntitySettingService) : base(validationEntitySettingService)
{
// no longer needed
//AddEmptyRuleFor(x => x.LastName, "Last Name is a required field!");
//AddEmptyRuleFor(x => x.FirstName, "First Name is a required field!");
//AddEmptyRuleFor(x => x.MiddleName, "Middle Name is a required field!");
}
}
这是 ExpressionHelper class,它提供了一种创建通用成员表达式作为对象的方法,可以在调用上面的 AddEmptyRuleFor 方法时传入该对象:
public static class ExpressionHelper
{
public static Expression<Func<TModel, TProperty>> CreateMemberExpression<TModel, TProperty>(PropertyInfo propertyInfo)
{
if (propertyInfo == null)
throw new ArgumentException("Argument cannot be null", "propertyInfo");
ParameterExpression entityParam = Expression.Parameter(typeof(TModel), "x");
Expression columnExpr = Expression.Property(entityParam, propertyInfo);
if (propertyInfo.PropertyType != typeof(T))
columnExpr = Expression.Convert(columnExpr, typeof(T));
return Expression.Lambda<Func<TModel, TProperty>>(columnExpr, entityParam);
}
public static object CreateMemberExpressionForProperty<TModel>(PropertyInfo property)
{
MethodInfo methodInfo = typeof(ExpressionHelper).GetMethod("CreateMemberExpression", BindingFlags.Static | BindingFlags.Public);
Type[] argumentTypes = new Type[] { typeof(TModel), property.PropertyType };
MethodInfo genericMethod = methodInfo.MakeGenericMethod(argumentTypes);
return genericMethod.Invoke(null, new object[] { property });
}
}