I use FluentValidation to validate my ASP.NET MVC 5.1 viewmodels (using the default unobtrusive client-side validation). I register/create my validators via Ninject (no attributes on the viewmodels):
FluentValidationModelValidatorProvider.Configure(x => x.ValidatorFactory = new NinjectValidatorFactory(_kernel));
AssemblyScanner.FindValidatorsInAssembly(Assembly.GetExecutingAssembly()).ForEach(match => _kernel.Bind(match.InterfaceType).To(match.ValidatorType));
I have a partial view that is used often throughout the application. This partial view has its own viewmodel. The "main" viewmodel (the one for the entire view) just inherits from this "partial" viewmodel.
public class IndexViewModel : PersonalInfoViewModel { ... }
The same pattern is used on the validators:
public class IndexValidator : PersonalInfoValidator { ... }
This works fine and the server-side validation works as well as the client-side validation on the "main" view. But the client-side validation on the partial view is not triggered (no data-val-*
attributes on input fields there).
My "main" view Index.cshtml
@model IndexViewModel
@Html.TextBoxFor(x => x.SomeProperty) // client-side validation works fine
@Html.Partial("PersonalInfo") // client-side validation in the partial view does not work (see below)
My partial view PersonalInfo.cshtml
:
@model PersonalInfoViewModel
@Html.TextBoxFor(x => x.FirstName) // client-side validation does not work
I noticed that it works when I change the model for the partial view to the "main" viewmodel:
@model IndexViewModel
@Html.TextBoxFor(x => x.FirstName) // client-side validation works
So I guess somewhere when building the client-side validation the correct validator does not get picked up and no data-val-*
attributes are injected into the HTML. But I can't changed the viewmodel on the partial view, because it's used on several different pages with different "main" views (all inherit from PersonalInfoViewModel though).
Any ideas on how to get my client-side validation working in this case?
Update
After a few hours of digging through the ASP.NET WebStack source, I found that the problem seems to occur in the TextBoxFor
method. There the ModelMetaData
is created from the model - and in there somewhere it starts to use IndexViewModel
instead of PersonalInfoViewModel
to get the metadata for client-side validation:
ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
Html.GetUnobtrusiveValidationAttributes("FirstName", metadata); // no client-side validation attributes found
But this generates the correct client-side validation attributes if I don't specify the metadata explicitly:
Html.GetUnobtrusiveValidationAttributes("FirstName");
Unfortunately, I have not found a way to use this knowledge for my advantage so far.
I wasn't able to find a nice solution to my problem, and didn't want to play around with the ASP.NET WebStack source anymore, so I settled with an ugly workaround:
I "manually" inject the missing data-val-*
attributes when rendering the input fields, like this:
@Html.TextBoxFor(x => x.FirstName, Html.GetUnobtrusiveValidationAttributes("FirstName"))
Since GetUnobtrusiveValidationAttributes
(called stand-alone) builds the correct HTML attributes I just take them and add it the to TextBox. Definitely not beautiful, but it works and I can go on with my work. If somebody has a better solution, I'd be very happy to hear it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With