ASP.NET MVC – Custom validation message for value types

Make your own ModelBinder by extending DefaultModelBinder:

public class LocalizationModelBinder : DefaultModelBinder

Override SetProperty:

        base.SetProperty(controllerContext, bindingContext, propertyDescriptor, value);

        foreach (var error in bindingContext.ModelState[propertyDescriptor.Name].Errors.
            Where(e => IsFormatException(e.Exception)))
        {
            if (propertyDescriptor.Attributes[typeof(TypeErrorMessageAttribute)] != null)
            {
                string errorMessage =
                    ((TypeErrorMessageAttribute)propertyDescriptor.Attributes[typeof(TypeErrorMessageAttribute)]).GetErrorMessage();
                bindingContext.ModelState[propertyDescriptor.Name].Errors.Remove(error);
                bindingContext.ModelState[propertyDescriptor.Name].Errors.Add(errorMessage);
                break;
            }
        }

Add the function bool IsFormatException(Exception e) to check if an Exception is a FormatException:

if (e == null)
            return false;
        else if (e is FormatException)
            return true;
        else
            return IsFormatException(e.InnerException);

Create an Attribute class:

[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = false)]
public class TypeErrorMessageAttribute : Attribute
{
    public string ErrorMessage { get; set; }
    public string ErrorMessageResourceName { get; set; }
    public Type ErrorMessageResourceType { get; set; }

    public TypeErrorMessageAttribute()
    {
    }

    public string GetErrorMessage()
    {
        PropertyInfo prop = ErrorMessageResourceType.GetProperty(ErrorMessageResourceName);
        return prop.GetValue(null, null).ToString();
    }
}

Add the attribute to the property you wish to validate:

[TypeErrorMessage(ErrorMessageResourceName = "IsGoodType", ErrorMessageResourceType = typeof(AddLang))]
    public bool IsGood { get; set; }

AddLang is a resx file and IsGoodType is the name of the resource.

And finally add this into Global.asax.cs Application_Start:

ModelBinders.Binders.DefaultBinder = new LocalizationModelBinder();

Cheers!

Leave a Comment