问题
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