4

How can I use resources from a different assembly to override the default attribute error messages in my MVC5 application?

My website is namespaced: Company.Web

My resources assembly is namespaced: Company.Web.Resources

I can easily localize attribute error messages individually using:

[Required(ErrorMessageResourceName = "PropertyValueRequired", ErrorMessageResourceType = typeof(Company.Web.Resources.Messages))]

However, since our error message is always "Required", I'd simply like to put the [Required] attribute without having to specify the resource name. I'd also like to override the default data type messages output by MVC which you can't do via an attribute.

The field {0} must be a date.

I'd like to be

Invalid date

I've seen examples where you can put the resource files in App_GlobalResources (with keys PropertyValueRequired, FieldMustBeDate, FieldMustBeNumeric) and setting ClientDataTypeModelValidatorProvider.ResourceClassKey, but I already have an external resources assembly I want to use.

I've tried using the following in my Global.asax with no luck:

ClientDataTypeModelValidatorProvider.ResourceClassKey = "Company.Web.Resources.Messages"

How can I accomplish this? Any ideas?

UPDATE (Partial Resolution)

I can solve my attribute-based problem simply by creating new validation adapters and using them in lieu of the default:

public class MyRequiredAttributeAdapter : RequiredAttributeAdapter
{
    public MyRequiredAttributeAdapter(ModelMetadata metadata, ControllerContext context, RequiredAttribute attribute)
        : base(metadata, context, attribute)
    {
        if (attribute.ErrorMessage.IsNullOrWhitespace() 
            && attribute.ErrorMessageResourceName.IsNullOrWhitespace() 
            && attribute.ErrorMessageResourceType == null)
        {
            attribute.ErrorMessageResourceType = typeof (Resources.Validation.Messages);
            attribute.ErrorMessageResourceName = "PropertyValueRequired";
        }
    }
}

Global.asax

DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(RequiredAttribute), typeof(MyRequiredAttributeAdapter));

However, this still leaves me scratching my head on how to override the default data type message for non-null properties such as DateTime and int. Also, I believe there are some I am unable to override because they are internal (DataTypeAttributeAdapter, CompareAttributeAdapter).

Jason Butera
  • 2,376
  • 3
  • 29
  • 46
  • Couldn't you just create your own attributes inheriting the built in attributes? – mxmissile Aug 01 '14 at 17:23
  • Yes, unfortunately that doesn't handle the built-in data type validation for dates and numbers. For example, when you have a non-nullable DateTime property on a model (without using any attributes at all), the message output is "The field {0} must be a date.". I want it to say "Invalid Date". – Jason Butera Aug 01 '14 at 17:32
  • possible duplicate of [How to change default validation error message in ASP.NET MVC?](http://stackoverflow.com/questions/6214066/how-to-change-default-validation-error-message-in-asp-net-mvc) – Yuliam Chandra Aug 01 '14 at 18:16
  • Not a duplicate. All those solutions rely on resources created within the same web assembly using App_GlobalResources. My resource strings need to derive from another assembly. – Jason Butera Aug 01 '14 at 18:35
  • Did you manage to find a full solution to this? I have the same issue. – RobHurd Mar 30 '15 at 03:45
  • This works perfectly for `Required` attributes, but it does not work with `EmailAddress` attributes, because there is no `EmailAddressAttributeAdapter` to override. – Rudey May 02 '17 at 15:06

2 Answers2

1

This might be quite late, but then here is a solution that should work based primarily on the logic behind your partial solution.

  1. Implement a custom RequiredAttribute for your project

    public class MyRequiredAttribute : RequiredAttribute
    {
        //Your custom code
    }
    
  2. Modify your MyRequiredAttributeAdapter code as shown. Notice that you now need to inherit from the generic DataAnnotationsModelValidator class, which allows you pass in your custom MyRequiredAttribute

    public class MyRequiredAttributeAdapter : DataAnnotationsModelValidator<MyRequiredAttribute>
    {
        public MyRequiredAttributeAdapter(ModelMetadata metadata, ControllerContext context, MyRequiredAttribute attribute)
            : base(metadata, context, attribute)
        {
            if (string.IsNullOrWhiteSpace(attribute.ErrorMessage)
                && string.IsNullOrWhiteSpace(attribute.ErrorMessageResourceName)
                && attribute.ErrorMessageResourceType == null)
            {
                attribute.ErrorMessageResourceType = typeof(Resources.Validation.Messages);
                attribute.ErrorMessageResourceName = "PropertyValueRequired";
            }
        }
    }
    
  3. Add this to Global.asax (modified from what you have in your partial solution)

    DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(MyRequiredAttribute), typeof(MyRequiredAttributeAdapter));
    
Soma Mbadiwe
  • 1,594
  • 16
  • 15
0

To override the default data type message for non-null properties such as DateTime and int,
implement an own MyClientDataTypeModelValidatorProvider based on the MVC ClientDataTypeModelValidatorProvider.
Add that instance to ModelValidatorProviders.Providers, and removed the default one.

So, put this into Global.asax:

var clientDataTypeModelValidatorProviderIndex = ModelValidatorProviders.Providers.FindIndex(modelValidatorProvider => modelValidatorProvider is ClientDataTypeModelValidatorProvider);
ModelValidatorProviders.Providers.RemoveAt(clientDataTypeModelValidatorProviderIndex);
ModelValidatorProviders.Providers.Add(new MyClientDataTypeModelValidatorProvider());

Tested with MVC 5

nvirth
  • 1,599
  • 1
  • 13
  • 21