Search code examples
c#asp.net-mvcninjectfluentvalidation

Selective validation of child properties - Fluent Validation in MVC


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?


Solution

  • 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:

    1. 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.
    2. 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.