Jan 17 2012

Customizing Error Messages in Asp.Net MVC

Category: MVC | Asp.netFrancesco @ 07:07

 

Error messages that are automatically displayed by Asp.Net Mvc in response to user wrong inputs come from 3 sources:

  • Errors that the developer adds manually to the ModelState. Such errors are under the full control of the user since they are handled manually, so there is not too much to say about them: I just advice to put them in a resource file, instead of mixing them with the code. This way the application can be easily globalized, and all messages can be easily changed without putting the fingers in the code.
  • Errors added automatically by the Model Binder during the Model Binding process. The Model Binder adds substantially two kind of error messages:
    • Wrong Format Error messages: they are added when the Model Binder is not able to parse an input string coming from the client into its destination type. This happens, for instance, when the user inserts alphabetic characters into an integer field. The standard error message used in this case by the Model Binder is taken from an internal resource file, and it is used just for the server side validation. Client Side validation uses a messages taken from a different source.
    • Implicit Required Field Error Message: properties that can’t have a null value, such as integers or floats properties are considered Required also if they are not explicitely marked as Required with a RequiredAttribute. On the server side this check is automatically performed by the Model Binder. The standard error message used in this case is taken from an internal resource file, and it is used for both server side and client side validation.
  • Error Messages coming from different Validator Providers:

Summing up, the messages automatically provided by the framework that we might want to customize are:

  1. Messages coming from validation attributes. In this case the same message is used on both the Client Side and the Server Side.
  2. Implicit Required Field Error Message. In this case the same message is used on both the Client Side and the Server Side.
  3. Wrong Format Error message on the Server Side
  4. Wrong Format Error message on the Client Side

All the above messages share a common format: they are not simple strings, but the are format strings with an hole {0}, that is automatically filled with the DisplayName of the property they refer to. Accordingly, when we customize them, we may put the same hole in our customized messages to ensure a better user experience.

The DisplayName is taken from the Name property of the DisplayAttribute, or from the DisplayNameAttribute.if the ViewModel property is decorated with any of these attributes. In the case of the DisplayAttribute if the ResourceType property is null the string contained in Name is used directly as DisplayName otherwise the Name string is used as a key to retrieve the value of the DisplayName from the resource file specified in ResourceType. The DisplayNameAttribute.instead, is more “primitive” and doesn’t allow the use of resource files, but just a simple string that must be passed as parameter. However, the DisplayNameAttribute is the only one supported in Mvc 2.

If the ViewModel property is not decorated with either the DisplayAttribute or the DisplayNameAttribute the DisplayName is set to the name of the ViewModel property.

Customizing error messages coming from validation attributes.

All validation attributes inherits from the ValidationAttribute class. Accordingly, they all have three properties that enable the developer to customize their error messages: ErrorMessage, ErrorMessageResourceType, and ErrorMessageResourceName. ErrorMessage can be set directly to a custom error message (with a hole for the DisplayName). The other two properties are useful if we prefer to store the custom message in a resource file;  ErrorMessageResourceType specifies the type associated to the resource file (typically the type name is equal to the the file name), and ErrorMessageResourceName is the key to lookup in the resource to get the error message.

Below two examples using the ErrorMessage:

[Required(ErrorMessage="Please insert a valid {0}") ]
[DisplayName("User name")]
public string UserName { get; set; }

or without the “hole”:

[Required(ErrorMessage="Please insert a valid user name") ]
[DisplayName("User name")]
public string UserName { get; set; }

and an example that uses a resource file:

[Required(ErrorMessageResourceType=typeof(Resource1), ErrorMessageResourceName="fieldRequired") ]
[DisplayName("User name")]
public string UserName { get; set; }

Customizing the Implicit Required Field Error message and the Wrong Format Error message on the Server Side

These messages can be customized by defining them in a Resource file and then assigning the name of the resource file into the static string property ResourceClassKey of the class DefaultModelBinder. The Implicit Required Field custom error message has to be put under a key named DefaultModelBinder_ValueRequired and the Wrong Format custom error message under a key named DefaultModelBinder_ValueInvalid. While the Implicit Required Field custom error message is used on both client side and server side the Wrong Format custom error message is used just on the server side.

The message has two “holes” {0} is for the value and {1} for the DisplayName of the field. The standard message for the English is: The value '{0}' is not valid for {1}.

A good place where to assign a value to the ResourceClassKey property is the global.asax:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    DefaultModelBinder.ResourceClassKey = "MyResources";
    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
}

Customizing the Wrong Format Error messages on the Client Side

This messages are provided by the ClientDataTypeModelValidatorProvider, and have just one “hole” for the DisplayName of the property in contrast with its server side counterpart that has two holes, one for the value and the other for the DisplayName. The reason of this difference is simple: the “holes” are filled on the server side when the value is still unknown.

Before Mvc4 the ClientDataTypeModelValidatorProvider had no extension point to customize the error message. Accordingly, the only clean way to customize this message is by substituting the ClientDataTypeModelValidatorProvider. Starting from  Mvc 4 the ClientDataTypeModelValidatorProvider  was enriched with a ResourceClassKey static string property that may be filled with the name of a custom resource class, that works similarly works as   the ResourceClasseKey property of the DefaultModelBinder. In this case the wrong numeric format error and the wrong date format errors must be provided respectively under the FieldMustBeNumeric and FieldMustBeDate keys.

In the Mvc Controls Toolkit we have substituted the ClientDataTypeModelValidatorProvider with another provider called ClientDataTypeModelValidatorProviderExt that works properly also with Mvc versions before version 4. It has extension points for specifying errorr message for both the Wrong Numeric Format error and another for the Wrong Date and Time Format error, and specifies the resource class as a type instead instead of as a string in order to increase the maintainability of the code. The customization may be performe by passing both a Resource file type and the key for the two error messages to static properties of the ClientDataTypeModelValidatorProviderExt class as shown below:

protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            MVCControlsToolkit.Core.ClientDataTypeModelValidatorProviderExt.ErrorMessageResources = typeof(MVCNestedModels.Models.Resource1);
            MVCControlsToolkit.Core.ClientDataTypeModelValidatorProviderExt.NumericErrorKey = "NumericError";
            MVCControlsToolkit.Core.ClientDataTypeModelValidatorProviderExt.DateTimeErrorKey = "DateError";
            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);
        }

for more details see here.

 

That’s all!

Stay Tuned

Francesco

Tags: , ,