4
votes

I have the following custom validation attribute, which derives from StringLengthAttribute:

public class StringLengthLocalizedAttribute : StringLengthAttribute
{
    public StringLengthLocalizedAttribute(int maximumLength) : base(maximumLength)
    {
        var translator = DependencyResolver.Current.GetService<ITranslator();
        var translatedValue = translator.Translate("MaxLengthTranslationKey", ErrorMessage);
        ErrorMessage = translatedValue.Replace("{MaxLength}", maximumLength.ToString());
    }
}

The only purpose of this custom attribute is to localize the ErrorMessage. The problem is, when I use this in my models it does not generate any client-side validation, but the standard StringLength attribute does.

I don't see how my attribute differs in any way - since it derives from the StringLength attribute I shouldn't have to implement any additional functionality to get client side validation working?

1

1 Answers

3
votes

If you look at the source code for DataAnnotationsModelValidatorProvider, you'll see in the method BuildAttributeFactoriesDictionary that specific types of attributes are registered for client side validation - you have created a new type, hence no client side validation.

Thankfully, this also has a public method to add your own adapter and is easy to use in the simple case you give:

Firstly, you need an adapter that will provide the client validation rules:

public class MyStringLengthAdapter : DataAnnotationsModelValidator<MyStringLengthAttribute>
{
    public MyStringLengthAdapter(ModelMetadata metadata, ControllerContext context, MyStringLengthAttribute attribute)
        : base(metadata, context, attribute)
    {
    }

    public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
    {
        return new[] { new ModelClientValidationStringLengthRule(ErrorMessage, Attribute.MinimumLength, Attribute.MaximumLength) };
    }
}

You then need to register this in the Application_Start method in Global.asax.cs like so:

DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof (MyStringLengthAttribute), typeof (MyStringLengthAdapter));