I'm trying to use #Html.ValidationMessageFor() for displaying errors in MVC,
and I'm trying to do something like: #Html.ValidationMessageFor(#ViewBag.Price) but I get syntax errors.
I want validation for this input:
input type="number" value="#ViewBag.Price" name="CurrentPrice"
You're getting syntax errors because ValidationMessageFor takes in a Func. You can't just use #ViewBag.Price in it and assume that it will work. The MSDN definition of that method is right here.
What you need to do is have that method be mapped to a specific field in your Model class (i.e. not the ViewBag) so that MVC knows precisely where to put the validation message should one come back after submission.
You could also instead just use ValidationMessage, which will take a field instead of a Func. A good example of using that can be found here.
Related
In MVC if you want to create an editor for a property or a display for you property you do something like that:
#Html.EditorFor(m=> m.MyModelsProperty);
#Html.DisplayFor(m=> m.MyModlesProperty);
Why do we have to pass a delegate why can't we just pass the model's property directlly? e.g.:
#html.EditorFor(Model.MyModlesProperty);
The reason for this is because of Metadata. You know, all the attributes you could put on your model, like [Required], [DisplayName], [DisplayFormat], ... All those attributes are extracted from the lambda expression. If you just passed a value then the helper wouldn't have been able to extract any metadata from it. It's just a dummy value.
The lambda expression allows to analyze the property on your model and read the metadata from it. Then the helper gets intelligent and based on the properties you have specified will act differently.
So by using a lambda expression the helper is able to do a lot more things than just displaying some value. It is able to format this value, it is able to validate this value, ...
I'd like to add, that besides the Metadata and making the Html helper strongly typed to the Model type, there's another reason:
Expressions allow you to know the name of the property without you hard coding strings into your project. If you check the HTML that's produced by MVC, you'll see that your input fields are named "ModelType_PropertyName", which then allows the Model Binder to create complex types that are passed to your Controller Actions like such:
public ActionResult Foo(MyModel model) { ... }
Another reason would be Linq to SQL. Expression Trees are the magic necessary to convert your Lambdas to SQL queries. So if you were to do something like:
Html.DisplayFor(p => p.Addresses.Where(j => j.Country == "USA"))
and your DbContext is still open, it would execute the query.
UPDATE
Stroked out a mistake. You learn something new every day.
The first example provides a strongly-typed parameter. It forces you to choose a property from the model. Where the second is more loosely-typed, you could put anything in it, even something that isn't valid property of the model.
Edit:
Surprisingly, I couldn't find a good example/definition of strong vs loose typing, so I'll just give a short example regarding this.
If the signature was #html.EditorFor(string propertyName); then I could make a typo when typing in the name and it would not be caught until run-time. Even worse, if the properties on the model changed, it would NOT throw a compiler error and would again not be detected until run-time. Which may waste a lot of time debugging the issue.
On the other hand with a lambada, if the model's properties changed you would get a compiler error and you would have to fix it if you wanted to compile your program. Compile-time checking is always preferred over run-time checking. This removes the chance of human error or oversight.
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
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");
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.
I believe that if both - xml validation, and validation in the action class are setup, then, irrespective of whether errors were discovered in the xml validation phase, the action class' validate method will be called. Building on this premise, how can I know that there were any xml validation errors from inside my action's validate() method (getActionErrors().size() == 0.. something like that).
My purpose is to set certain variables of the action class if there were validation errors before sending control back to the jsp. (setting them inside prepare would be wrong, as prepare would execute irrespective of whether there were errors)
You can use getFieldErrors() which returns
Map with errors mapped from fieldname (String) to Collection of String
error messages
There are also helper methods such as hasActionErrors() and hasFieldErrors() which will help you determine if errors already exist.
Note that the first tells you if there are Action-level errors and the latter helps determine if there are specific, field associated errors.
It's easy to set our action not to validate the input just hooking up the attribute like
[HttpPost, ValidateInput(false)]
public ActionResult Signup(SignupModel model)
{
...
}
But I was wondering, is there a way to only do this in just one form field? and not all of them in the actual <form>
or, I have to use this and then worry about encoding properly all other fields?
You should not rely on ValidateInput to 'encode' your values. It doesn't encode values - it just rejects some values outright. And even if you use it, you still must encode all your values that are user-entered and displayed on the site in any way.
In fact, because of that - I've never used that validation myself. For example, if all I did was rely on that validation, people would not be able to enter some very basic things in forms like this one, such as trying to show example HTML.
But even the MSDN documentation and every book I've read said that the ASP.NET validation there does not protect you against every possible malicious input. So essentially, you can not rely on it to protect your users. You still must encode values you are displaying (and you should encode them only as you are displaying them, otherwise you'll end up with all sorts of display bugs where you've double-encoded things)
Using MVC3 , the attribute can be applied to Model by specifying SkipRequestValidation.
I'm using the UpdateModel method for validation. How do I specify the text for the error messages as they appear in the validation summary?
Sorry, I wasn't entirely clear. When I call UpdateModel(), if there is parsing error, for example if a string value is specified for a double field, a "SomeProperty is invalid" error message is automatically added to the ModelState.
How do I specify the text for said automatically generated error message?
If I implement IDataErrorInfo as suggested, it's error message property gets called for every column, regardless of whether the default binder deems it valid or not.
I'd have to reimplement the parse error catching functionality that I get for free with the default binder.
Incidentally, the default "SomeProperty is invalid" error messages seem to have mysteriously dissappeared in the RC. A validation summary appears and the relevant fields are highlighted but the text is missing! Any idea why this is?
Thanks again and I hope all this waffle makes sense!
This tutorial is a good example of the IDataErrorInfo technique - it makes adding validation parameters easy by adding them as attributes directly to the properties of the model classes.
These examples also may help - slightly different approaches to validating.
Additionally, this creative idea (which also implements IDataErrorInfo) may be a help to you.
Implement IDataErrorInfo on your model.