开发者

Client-side validation does not work when inherting from RequiredAttribute in ASP.NET MVC 3?

I created an inherited attribute like this in ASP.NET MVC3:

public sealed class RequiredFromResourceAttribute : RequiredAttribute
{
    public RequiredFromResourceAttribute(string errorResourceName, string errorResourceTypeName)
    {
        this.ErrorMessageResourceName = errorResourceName;
        this.ErrorMessageResourceType = Type.GetType(errorResourceTypeName);
    }
}

And use it like this:

[RequiredFromRes开发者_如何学Cource("Title", "Resources.Resource, MyProject.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")]
public string Title { get; set; }

It didn't work and the MVC ignored it. Then I create a simpler class which just inherited from RequiredAttribute like this:

public class MyRequiredAttribute : RequiredAttribute
{
}

I use it like that I said. But it didn't work again.

Although, all these ways work on "DisplayNameAtrribute" perfectly.

What is the problem?


You can fix this by adding the following code in Global.asax: (found the answer here)

DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(RequiredLocalizableAttribute), typeof(RequiredAttributeAdapter));

Alternatively, using marcind's solution, I found that the constructor for ModelClientValidationRequiredRule requires an error message. Here is an updated version that includes the display name for the field:

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        string msg = FormatErrorMessage(metadata.GetDisplayName());
        yield return new ModelClientValidationRequiredRule(msg);
    }


It's only client-side validation that does not work with inherited attributes. The reason for that is that MVC uses strict type equality when mapping server-side attributes to client validation behaviors.

To work around this you will need your custom attribute to implement IClientValidatable:

public class MyRequiredAttribute : IClientValidatable {
    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) {
         yield return new ModelClientValidationRequiredRule();
    }
}


Building on the above, the complete attribute for LocalizedRequiredAttribute using a default resource string of Resource.ValueRequired which is defined in my resources as "The {0} field is required."

public class LocalizedRequiredAttribute : RequiredAttribute, IClientValidatable 
{
    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var msg = new ResourceManager(ErrorMessageResourceType).GetString(ErrorMessageResourceName);
        yield return new ModelClientValidationRequiredRule(string.Format(msg, metadata.DisplayName));
    }

    public LocalizedRequiredAttribute(string errorResourceName = null, string errorResourceTypeName = null)
    {
        this.ErrorMessageResourceName = string.IsNullOrEmpty(errorResourceName) ? nameof(Resource.ValueRequired) : errorResourceName;
        this.ErrorMessageResourceType = string.IsNullOrEmpty(errorResourceTypeName) ? typeof(Resource) : Type.GetType(errorResourceTypeName);
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜