2012-03-08 3 views
2

Учитывая класс валидатора, который выглядит как этотСвободно правила валидации, подмножество и раскрой

public class SomeValidator : AbstractValidator<SomeObject> 
{ 
     public SomeValidator(){ 
      RuleSet("First", 
       () => { 
        RuleFor(so => so.SomeMember).SetValidator(new SomeMemberValidator()) 
      }); 
      RuleSet("Second", 
       () => ... Code Does Not Matter ...); 
      RuleSet("Third", 
       () => ... Code Does Not Matter ...); 
     } 
} 

И другое, чтобы сделать внутреннюю Validation-членом

public class SomeMemberValidator: AbstractValidator<SomeMember> 
{ 
     public SomeValidator(){ 
      RuleSet("Fourth", 
       () => { 
        ... Code Does Not Matter ... 
      }); 
     } 
} 

Вопрос, я хочу, чтобы запустить определенные наборы правил: «Первый», «Второй» и «Четвертый». Я не хочу, чтобы «Третий» запускался.

Учитывая, что сигнатура метода Validate принимает только один аргумент набора правил, я не вижу никакого способа сделать это. Есть «*», но я не хочу запускать все правила.

Пожалуйста, помогите.

ответ

5

Вы можете выполнить несколько RuleSet, но я не думаю, что вы можете выполнить внутренний RuleSet.

validator.Validate(new ValidationContext<SomeObject>(person, new PropertyChain(), new RulesetValidatorSelector("First", "Second", "Fourth"))); 

Source

Другой вариант состоит в изучении исходного кода и попытаться думать способ сделать это. Третий параметр ValidationContext - это интерфейс, IValidatorSelector, может быть, вам повезет с пользовательским классом.

+0

Я надеялся избежать возможности проникновения в исходный код, если это возможно, но мы увидим. Спасибо за помощь. – Alwyn

6

Вы можете использовать конструктор валидатора вместо RuleSet в качестве обходного пути для этой проблемы. Просто создайте enum внутри класса validator, а затем используйте его значение при создании валидатора.

В этом случае правильные правила будут активированы в зависимости от того, какой режим установлен в конструкторе.

public class UserValidator : AbstractValidator<User> 
{ 
    public enum Mode 
    { 
     Create, 
     Edit 
    } 

    public UserValidator() 
    { 
     // Default rules... 
    } 

    public UserValidator(UserValidator.Mode mode) 
     : this() 
    { 
     if (mode == Mode.Edit) 
     { 
      // Rules for Edit... 

      RuleFor(so => so.SomeMember) 
       .SetValidator(
        new SomeMemberValidator(SomeMemberValidator.Mode.SomeMode)) 
     } 

     if (mode == Mode.Create) 
     { 
      // Rules for Create... 

      RuleFor(so => so.SomeMember) 
       .SetValidator(
        new SomeMemberValidator()) 
     } 
    } 
} 

Я думаю, что это на самом деле более гибкий метод, чем использование RuleSet.

Существует только одна небольшая проблема относительно интеграции FluentValidation MVC: User класс не может иметь атрибут [Validator(typeof(UserValidator))], потому что UserValidator будет затем создан с помощью конструктора по умолчанию, прежде чем делать что-либо в методе контроллера.

Валидатор необходимо создать и вызвать вручную. Например, это так:

public class UserController : Controller 
{ 
    [HttpPost] 
    public ActionResult Create(User userData) 
    { 
     var validator = new UserValidator(UserValidator.Mode.Create); 

     if (ValidateWrapper(validator, userData, this.ModelState)) 
     { 
      // Put userData in database... 
     } 
     else 
     { 
      // ValidateWrapper added errors from UserValidator to ModelState. 
      return View(); 
     } 
    } 

    private static bool ValidateWrapper<T>(FluentValidation.AbstractValidator<T> validator, T data, ModelStateDictionary modelState) 
    { 
     var validationResult = validator.Validate(data); 

     if (!validationResult.IsValid) 
     { 
      foreach (var error in validationResult.Errors) 
       modelState.AddModelError(error.PropertyName, error.ErrorMessage); 

      return false; 
     } 

     return true; 
    } 
} 
Смежные вопросы