I am having a property in my View Model which can accept integer and nullable values:
[Display(Name = "Code Postal")]
public int? CodePostal { get; set; }
When I type in string values, how can display another message than the default one:
The field Code Postal must be a number.
Thanks
It's little disappointing to see about the amount of work we have to do when all we want is a custom error message for the implicit validations done by the default model binder. The reason is the
DefaultModelBinder
hides some important methods as private especially theGetValueInvalidResource
andGetValueRequiredResource
. I hope they will take care of this in future.I was trying to give a generic solution for the problem avoiding to create model binders for every type.
Honestly I haven't tested the below implementation in all the cases(ex. when binding collections) but did in basic levels.
So here is the approach.
We have two custom attributes that helps to pass custom error message for our custom model binder. We could have a base class but that's fine.
Here is the model binder this is generic and independent of types and takes care of customizing error messages for both required and invalid validations.
We are overriding the
OnPropertyValidated
method just to override the implicit required error message thrown by the default model binder, and we are overriding theSetProperty
just to use our own message when the type is not valid.Set our custom binder as the default in Global.asax.cs
And you can decorate your properties like this..
Alternative - rewrite resource strings
The easiest way is to replace default validation resource strings. This other SO answer will help you with that.
But you have to remember that these strings will them be used on all of your models not just particular property of some class.
Regular expression attribute
Add an additional attribute to your property:
Even though you set regular expression on a non-string property this should still work. If we look at validation code it's like this:
As we can see, this validator automatically converts the value to string. So if your value is a number it doesn't really matter because it will be converted to a string and validated by your regular expression.
You could write a metadata aware attribute:
and a custom model binder that uses this attribute because it is the default model binder that adds the hardcoded error message you are seeing when it binds those integral types from the request:
which will be registered in
Application_Start
:From this moment on things get pretty standard.
View model:
Controller:
View: