Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET MVC + FluentValidation + PartialView > no client-side validation

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.

like image 755
Hannes Sachsenhofer Avatar asked Feb 25 '14 10:02

Hannes Sachsenhofer


1 Answers

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.

like image 118
Hannes Sachsenhofer Avatar answered Sep 28 '22 22:09

Hannes Sachsenhofer