4

First of all, I have to say that I understand how Data Annotation -based Model Validation works in ASP.NET MVC4 and I have it successfully implemented with DataAnnotationsModelValidatorProvider. So I don't need assistance on setting it up.

But when it comes down to HtmlHelpers, I'm struggling with trying to figure the context of the error message. And by saying context, I mean which error we're talking about. Which Attribute returned the error?

What I can get, is the Key for the error and the current ErrorMessage but programmatically, there's nothing, that at least I'm aware of, that would communicate which error we're talking about. Whether it was Required attribute or some other attribute, there's not way that I can find how to distinguish them.

Let's open the scenario a little bit. I have custom HtmlHelpers to render ContentEditable elements. For example Html.ContentEditableValidationMessageFor(m => m.firstName);. It will output something like this:

<span contenteditable="true" data-valmsg-for="firstName" data-valmsg-replace="Please provide first name" class="field-validation-error">Please provide first name</span>

Now, I do have a jQuery plugin to handle and persist the changes in the contenteditable element and it will persist them into the backend. However, the UI has nothing that would say which error message we're talking about. Humans can easily see it's the RequiredAttribute, but programmatically there's no data to differentiate it from some MinLengthAttribute for example.

In this scenario, if I would simply use the data-valmsg-for="firstName" as the key for the localization, that'd return the same error message for all the errors concerning the same property.

To Round it Up

What would be the Best Practise, when ModelState is available, to emit a unique ID for ModelError? Considering I'm using ASP.NET MVC4 and DataAnnotationsModelValidatorProvider.

I can think of tons of ways to "Hack it Together" but I would like to use the ModelState and whatever MVC provides. If it all goes down to writing a custom ModelValidatorProvider, then I'm all open for it. As long as it is the best and most sustainable way of going about it. I'm all for Doing More Now and Less Later than Hacking it Now and Hacking it Forever to Keep It Working

Liam
  • 27,717
  • 28
  • 128
  • 190
Jani Hyytiäinen
  • 5,293
  • 36
  • 45
  • This is a very interesting question to me. What was the basis of your hack using reflection? Like you, the phrase "well you can do that via reflection" often means setting yourself up for code that will inevitably be poorly maintained. Will be keeping an eye on this one... – Moby's Stunt Double Apr 05 '13 at 20:40
  • Are you wanting the data on client or server side? – Jared Apr 08 '13 at 21:00
  • Any update on your progress? – Tom Riley Apr 09 '13 at 08:06
  • I will post my current reflection based implementation as soon as possible since we didn't get anything that could be considered as best practise. I'm also considering to submit this as a request to the MVC team. – Jani Hyytiäinen Apr 10 '13 at 14:27

2 Answers2

4

Can you give some context around the need to know which rule triggered the validation error, could it be a case of you trying to do something you shouldn't have too?

In general I use FluentValidation (http://fluentvalidation.codeplex.com/wikipage?title=mvc) in place of Data Annotation validation for many reasons, de-cluttering models, unit testing validation logic, allowing vastly more complex validation that include business logic. If your free to use 3rd party libraries I'd give it a look as it has always solved any validation problems I've had in the past.

It lets you write c# code that deals with your model validation via a fluent API. It has an MVC extension that wires everything up for you so other than creating the models validation class there is little impact from then on. An example for your code snippet above would be...

RuleFor(modelname => modelname.FirstName).NotEmpty().WithMessage("lease provide first name");
Tom Riley
  • 1,701
  • 2
  • 21
  • 43
2

Even implementing ModelValidatorProvider will not help, it is just a mechanism to provide ModelValidators based on Model Metadata. When during model binding process in a controller action ModelValidators are being invoked the result is just ModelValidationResult which only contains MemberName and a text Message.

I think there is a dirty way to find out which ModelValidator is failed by checking the error message like this:

var modelErrors = ModelState.Where(m => m.Value.Errors.Count > 0).Select(m => new { Name=m.Key , Errors=m.Value.Errors});

by checking ErrorMessage of Errors for each key in modelErrors against ValidatorProvider error messages you can find out the error belongs to which Validator.

Kambiz Shahim
  • 2,560
  • 14
  • 21
  • 1
    Thanks. But I'm already using a dirty way through reflection to get any ValidationAttributes of the Model property being validated. It's looking for the ErrorResourceKey of the attribute which outputs the same errorMessage as currently is populated in the ModelState. That way I can concatenate the property name and the error resource key to get a unique key for the property error. – Jani Hyytiäinen Apr 09 '13 at 20:37