I am trying to figure out why my FluentValidation
is not unobtrusively validating some of my View Model properties.
I installed, via NuGet, the FluentValidation package for MVC3:
Install-Package FluentValidation.MVC3
Results:
<package id="FluentValidation" version="5.0.0.1" targetFramework="net45" />
<package id="FluentValidation.MVC3" version="5.0.0.1" targetFramework="net45" />
The properties that are not being validated are some members of a Guitar class object, declared in my View model. The Guitar.ProductionYear property is getting the unobtrusive validation code but the other 2 properties of the Guitar object are not.
public Guitar Guitar1 { get; set; }
public Guitar Guitar2 { get; set; }
public Guitar Guitar3 { get; set; }
I read the FluentValidation docs, and now specifically about the limitations regarding FluentValidation's client-side validation of lists but this is not a list so I am hoping someone can see what's wrong and/or offer some suggestions.
I also tried using a custom Guitar object validator but still get the same results
Observations
Example
<!-- Unobtrusive JS generated-->
<input type="text" value="" name="FirstName" id="FirstName" data-val-required="'First Name' must not be empty." data-val="true" class="input-validation-error">
<div class="messageBottom">
<span data-valmsg-replace="true" data-valmsg-for="FirstName" class="field-validation-error"><span for="FirstName" generated="true" class="">'First Name' must not be empty.</span>
</span>
</div>
<!-- Unobtrusive JS Partially generated for Guitar object-->
<input type="text" value="" name="Guitar.Make" id="Guitar_Make" placeholder="Make">
<div class="messageBottom">
<span data-valmsg-replace="true" data-valmsg-for="Guitar1.Make" class="field-validation-valid"></span>
</div>
<input type="text" value="" name="Guitar1.Model" id="Guitar1_Model" placeholder="Model">
<div class="messageBottom">
<span data-valmsg-replace="true" data-valmsg-for="Guitar1.Model" class="field-validation-valid"></span>
</div>
<input type="text" value="" name="Guitar1.ProductionYear" id="Guitar1_ProductionYear" data-val-number="The field ProductionYear must be a number." data-val="true" placeholder="Production Year" class="valid">
<div class="messageBottom">
<span data-valmsg-replace="true" data-valmsg-for="Guitar1.ProductionYear" class="field-validation-valid">
</span>
</div>
Thanks
Global.asax.cs
FluentValidationModelValidatorProvider.Configure();
The View Model
[FluentValidation.Attributes.Validator(typeof(CustomerViewModelValidator))]
public class CustomerViewModel
{
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Display(Name = "Last Name")]
public string LastName { get; set; }
[Display(Name = "Phone")]
public string Phone { get; set; }
[Display(Name = "Email")]
public string EmailAddress { get; set; }
[Display(Name = "Guitar 1")]
public Guitar Guitar1 { get; set; }
[Display(Name = "Guitar 2")]
public Guitar Guitar2 { get; set; }
[Display(Name = "Guitar 3")]
public Guitar Guitar3 { get; set; }
}
The Custom Guitar Object Validator
public class GuitarValidator : AbstractValidator<Guitar>
{
public GuitarValidator()
{
RuleFor(x => x.Make).NotEmpty();
RuleFor(x => x.Model).NotEmpty();
RuleFor(x => x.ProductionYear).NotEmpty();
}
}
The View Model Validator
public class CustomerViewModelValidator : AbstractValidator<CustomerViewModel>
{
public CustomerViewModelValidator()
{
RuleFor(x => x.FirstName).NotNull();
RuleFor(x => x.LastName).NotNull();
RuleFor(x => x.Phone).NotNull();
RuleFor(x => x.EmailAddress).NotNull();
//1st Guitar Object is Required
RuleFor(x => x.Guitar).SetValidator(new GuitarValidator());
}
}
The View
<!-- Guitar Object #1 -->
<div id="cosponsorsTemplate_1">
<div class="formColumn1">@Html.LabelFor(x=>x.Guitar1)</div>
<div class="formColumn2">@Html.TextBoxFor(x => x.Guitar1.Make, new { Placeholder = "Make" })
<div class="messageBottom">@Html.ValidationMessageFor(x => x.Guitar1.Make)</div>
</div>
<div class="formColumn3">@Html.TextBoxFor(x => x.Guitar1.Model, new { Placeholder = "Model" })
<div class="messageBottom">@Html.ValidationMessageFor(x => x.Guitar1.Model)</div>
</div>
<div class="formColumn4">@Html.TextBoxFor(x =>x.Guitar1.ProductionYear, new { Placeholder = "Production Year" })
<div class="messageBottom">@Html.ValidationMessageFor(x => x.Guitar1.ProductionYear)</div>
<a class="icon delete" data-delete-id="1">Delete</a>
</div>
</div>
<!-- Guitar Object #2 -->
<div id="cosponsorsTemplate_2">
<div class="formColumn1">@Html.LabelFor(x=>x.Guitar2)</div>
<div class="formColumn2">@Html.TextBoxFor(x => x.Guitar2.Make, new { Placeholder = "Make" })
<div class="messageBottom">@Html.ValidationMessageFor(x => x.Guitar2.Make)</div>
</div>
<div class="formColumn3">@Html.TextBoxFor(x => x.Guitar2.Model, new { Placeholder = "Model" })
<div class="messageBottom">@Html.ValidationMessageFor(x => x.Guitar2.Model)</div>
</div>
<div class="formColumn4">@Html.TextBoxFor(x => x.Guitar2.ProductionYear, new { Placeholder = "Production Year" })
<div class="messageBottom">@Html.ValidationMessageFor(x => x.Guitar2.ProductionYear)</div>
<a class="icon delete" data-delete-id="2">Delete</a>
</div>
</div>
<!-- Guitar Object #3 -->
<div id="cosponsorsTemplate_3">
<div class="formColumn1">@Html.LabelFor(x=>x.Guitar3)</div>
<div class="formColumn2">@Html.TextBoxFor(x => x.Guitar3.Make, new { Placeholder = "Make" })
<div class="messageBottom">@Html.ValidationMessageFor(x => x.Guitar3.Make)</div>
</div>
<div class="formColumn3">@Html.TextBoxFor(x => x.Guitar3.Model, new { Placeholder = "Model" })
<div class="messageBottom">@Html.ValidationMessageFor(x => x.Guitar3.Model)</div>
</div>
<div class="formColumn4">@Html.TextBoxFor(x => x.Guitar3.ProductionYear, new { Placeholder = "Production Year" })
<div class="messageBottom">@Html.ValidationMessageFor(x => x.Guitar3.ProductionYear)</div>
<a class="icon delete" data-delete-id="3">Delete</a>
</div>
</div>