问题
I'm using Fluent Validation with the Ninject.Web.Mvc.FluentValidation library to automatically wire up all of my validators (and use dependency injection to create the validators).
I created the following Models:
public class Parent
{
    public string Name { get; set; }
    public Child Child1 { get; set; }
    public Child Child2 { get; set; }
}
public class Child
{
    public string ChildProperty { get; set; }
}
With the following validators:
public class ParentValidator : AbstractValidator<Parent>
{
    public ParentValidator()
    {
         RuleFor(model => model.Name).NotEmpty();
         RuleFor(model => model.Child1).SetValidator(new ChildValidator());
    }
}
public class ChildValidator : AbstractValidator<Child>
{
    public ChildValidator()
    {
        RuleFor(model => model.ChildProperty).NotEmpty();
    }
}
My Views:
@model Parent
@using(Html.BeginForm())
{
    @Html.EditorFor(model => model.Name)
    @Html.ValidationMessageFor(model => model.Name)
    @Html.EditorFor(model => model.Child1)
    @Html.EditorFor(model => model.Child2)
    <input type="submit" value="Save" />
}
@model Child
@Html.EditorFor(model => model.ChildProperty)
@Html.EditorFor(model => model.ChildProperty)
What I am trying to accomplish is to have a parent model that has two child properties. Child1's property is required but Child2's property is optional. This works fine under normal circumstances, but when I use the Ninject module to wire up the validators automatically, then it is detecting that there is a validator type for the Child class and wiring up all of the Child properties on the Parent.
Is there any way I can prevent this from happening without getting rid of the Ninject module?
回答1:
Since the auto-wireup wouldn't have a way to conditionally understand when to apply the ChildValidator class during model binding, it seems like you have a few alternatives:
- Decide if reuse of the child view models is that important. Faced with this situation, I would probably collapse the children into the parent for this view if the Child objects weren't very complex and there weren't more than a couple of views that used Child objects separately. I'm always a bit more reluctant to be super-DRY with view models, since page structures tend to diverge over time in my experience.
- Clear ModelState errors for Child2. From here, you could take complete control of validation for Child2, including a separate validator for Child2 altogether in this unique context and applying it manually. Which is one of the reasons I love FluentValidation - the ability to apply different validation logic to the same view model in different contexts, unlike data annotations.
The value of auto-wireup (i.e., all the extra code it precludes) would rule out the option of turning that off for this one case, IMO.
回答2:
You forget to set validator to second child property:
public class ParentValidator : AbstractValidator<Parent>
{
    public ParentValidator()
    {
         RuleFor(model => model.Name).NotEmpty();
         RuleFor(model => model.Child1).SetValidator(new ChildValidator());
         RuleFor(model => model.Child2).SetValidator(new ChildValidator());
    }
}
回答3:
If you don't want to auto wireup child validators you can add empty interface to child validator:
public class PersonalDataValidator : AbstractValidator, IChildValidator
And then in your factory:
public class FluentValidatorFactory : ValidatorFactoryBase
{
    private readonly IKernel _kernel;
    public FluentValidatorFactory(IKernel kernel)
    {
        _kernel = kernel;
    }
    public override IValidator CreateInstance(Type validatorType)
    {
        IValidator validator = _kernel.Resolve(validatorType) as IValidator;
        ////we dont want that windosr auto wires up all child validators. 
        var childValidator = validator as IChildValidator;
        if (childValidator == null)
        {
            return validator;
        }
            return null;
    }
}
来源:https://stackoverflow.com/questions/8991314/selective-validation-of-child-properties-fluent-validation-in-mvc