2016-03-08 2 views
1

У меня есть scneario, в котором я хочу использовать отражение для проверки, используя FluentValidation. Коснуться, как это:Как использовать отражение в FluentValidation?

public class FooValidator : AbstractValidator<Foo> 
{ 
    public FooValidator(Foo obj) 
    { 
     // Iterate properties using reflection 
     var properties = ReflectionHelper.GetShallowPropertiesInfo(obj); 
     foreach (var prop in properties) 
     { 
      // Create rule for each property, based on some data coming from other service... 
      //RuleFor(o => o.Description).NotEmpty().When(o => // this works fine when foo.Description is null 
      RuleFor(o => o.GetType().GetProperty(prop.Name)).NotEmpty().When(o => 
      { 
       return true; // do other stuff... 
      }); 
     } 
    } 
} 

Вызов к ReflectionHelper.GetShallowPropertiesInfo(obj) возвращает «мелкие» свойства объекта. Затем для каждого свойства создаю правило. Это мой код для просмотра свойств объекта:

public static class ReflectionHelper 
{ 
    public static IEnumerable<PropertyInfo> GetShallowPropertiesInfo<T>(T o) where T : class 
    { 

     var type = typeof(T); 
     var properties = 
      from pi in type.GetProperties(BindingFlags.Public | BindingFlags.Instance) 
      where pi.PropertyType.Module.ScopeName == "CommonLanguageRuntimeLibrary" 
       && !(pi.PropertyType.IsGenericType && pi.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>)) 
      select pi; 

     return properties; 
    } 
} 

Этот код компиляции и может быть выполнена

IValidator<Foo> validator = new FooValidator(foo); 
var results = validator.Validate(foo); 

Но он не работает должным образом (проверка никогда не подведет). Есть ли способ достичь этого?

Примечания: код Demo можно найти Int Github в FluentValidationReflection

ответ

1

Наконец я нашел решение, которое работает. Я создал пользовательский PropertyValidator, который принимает параметр PropertyInfo:

public class CustomNotEmpty<T> : PropertyValidator 
{ 
    private PropertyInfo _propertyInfo; 

    public CustomNotEmpty(PropertyInfo propertyInfo) 
     : base(string.Format("{0} is required", propertyInfo.Name)) 
    { 
     _propertyInfo = propertyInfo; 
    } 

    protected override bool IsValid(PropertyValidatorContext context) 
    { 
     return !IsNullOrEmpty(_propertyInfo, (T)context.Instance); 
    } 

    private bool IsNullOrEmpty(PropertyInfo property, T obj) 
    { 
     var t = property.PropertyType; 
     var v = property.GetValue(obj); 

     // Omitted for clarity... 
    } 
} 

И метод расширения для IRuleBuilder:

public static class ValidatorExtensions 
{ 
    public static IRuleBuilderOptions<T, T> CustomNotEmpty<T>(
     this IRuleBuilder<T, T> ruleBuilder, PropertyInfo propertyInfo) 
    { 
     return ruleBuilder.SetValidator(new CustomNotEmpty<T>(propertyInfo)); 
    } 
} 

С этим я могу изменить мой FooValidator следующим образом:

public class FooValidator : AbstractValidator<Foo> 
{ 
    public FooValidator(Foo obj) 
    { 
     // Iterate properties using reflection 
     var properties = ReflectionHelper.GetShallowPropertiesInfo(obj); 
     foreach (var prop in properties) 
     { 
      // Create rule for each property, based on some data coming from other service... 
      RuleFor(o => o) 
       .CustomNotEmpty(obj.GetType().GetProperty(prop.Name)) 
       .When(o => 
      { 
       return true; // do other stuff... 
      }); 
     } 
    } 
} 

И теперь я могу использовать Reflection для добавления правил для определенных свойств