Environment:
I am using MVC4, Razor 2 and FluentValidation.MVC4 (3.4.6.0).
Scenario:
I have a complex view model for a particular page which also has a child view model on it as follows:
public class ProfileViewModel
{
public string FirstName {get; set;}
public PhoneNumberViewModel Primary {get; set;}
// ... other stuff ... //
}
public class PhoneNumberViewModel
{
public string AreaCode { get; set; }
public string Exchange { get; set; }
public string Suffix { get; set; }
public string Extension { get; set; }
}
This profile can be edited and POSTed back for updating. I have created Fluent Validators for both as follows:
public class ProfileViewModelValidator : AbstractValidator<ProfileViewModel>
{
public ProfileViewModelValidator()
{
RuleFor(m => m.FirstName).NotEmpty().WithMessage("Please enter a First Name,");
RuleFor(m => m.Primary).SetValidator(new PhoneNumberViewModelValidator()).WithMessage("Hello StackOverflow!");
// ... other validation ... //
}
}
public class PhoneNumberViewModelValidator : AbstractValidator<PhoneNumberViewModel>
{
public PhoneNumberViewModelValidator()
{
RuleFor(m => m.AreaCode).NotEmpty();
}
}
And then, of course, I have views to display everything.
Profile View Snippet:
...
@Html.TextBoxFor(m => m.FirstName)
@Html.EditorFor(m => m.PrimaryPhoneNumber)
...
Phone Number Editor Template Snippet:
...
@Html.ValidationLabelFor(m => m, "Primary Phone:")
@Html.TextBoxFor(m => m.AreaCode)
@Html.TextBoxFor(m => m.Exchange)
@Html.TextBoxFor(m => m.Suffix)
@Html.TextBoxFor(m => m.Extension)
@Html.ValidationMessageFor(m => m)
...
If it's relevant, I have things set up so that it automatically wires up validators with the various objects. I don't actually even need the .SetValidator()
line above... everything is validated anyway because of wire up.
Objective:
If I don't enter a first name, I get the error message provided above in the area created by ValidationMessageFor. However, if any of the elements of the child PhoneNumberViewModel fail validation, I get nothing. The Text Boxes highlight red, which is fantastic, but I do not get the message I supplied in the .WithMessage()
, indicating that my child property is invalid.
Currently I am achieving it by extra work in my controller... that looks for errors on the child objects and then adds errors to the parent object. This approach smells really, really bad. It's putting validation-related concerns in the controller, and I just don't want them there. Not to mention it also ends up having a lot of indexing by strings to dig into the ModelState, and it's just... gross.
Is there a simple way to define a validation rule for the ProfileViewModelValidator that will add errors for the ProfileViewModel if the child fails to validate? And/or should it be working, but am I doing something wrong? I've searched and searched, but I cannot find a satisfactory solution.
Thanks for your time!