开发者

Client-side validation for custom ValidationAttribute with AttributeTargets.Class

开发者 https://www.devze.com 2023-03-01 13:34 出处:网络
Is it possible to implement client-site validation for custom ValidationAttribute, which is used in Class scope? For example my MaxLengthGlobal, which should assure global max limit for all input fiel

Is it possible to implement client-site validation for custom ValidationAttribute, which is used in Class scope? For example my MaxLengthGlobal, which should assure global max limit for all input fields.

[AttributeUsage(AttributeTargets.Class)]
public class MaxLengthGlobalAttribute : ValidationAttribute, IClientValidatable
{
    public int MaximumLength
    {
        get;
        private set;
    }

    public MaxLengthGlobalAttribute(int maximumLength)
    {
        this.MaximumLength = maximumLength;
    }

    public override bool IsValid(object value)
    {
        var properties = TypeDescriptor.GetProperties(value);

        foreach (PropertyDescriptor property in properties)
        {
            var stringValue = property.GetValue(value) as string;

            if (stringValue != null && (stringValue.Length > this.MaximumLength))
            {
                return false;
            }
        }

        return true;
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {       
        va开发者_开发问答r rule = new ModelClientValidationRule
        {
            ErrorMessage = this.FormatErrorMessage(metadata.GetDisplayName()),
            ValidationType = "maxlengthglobal",
        };

        rule.ValidationParameters.Add("maxlength", this.MaximumLength);         
        yield return rule;
    }
}

Thank you.


I found this answer while looking for a solution to the same problem, and came up with a workaround.

Instead of 1 ValidationAttribute, have 2:

1.) A ServerValidationAttribute will be on the class, and will not implement IClientValidatable.

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class MyCustomServerValidationAttribute : ValidationAttribute
{
    public override bool IsValid(object value)
    {
        // remember to cast to the class type, not property type
        // ... return true or false
    }
}

2.) A ClientValidationAttribute will be on the field / property, and will implement IClientValidatable, but the IsValid override always returns true.

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, 
    AllowMultiple = false, Inherited = true)]
public class MyCustomClientValidationAttribute : ValidationAttribute, 
    IClientValidatable
{
    public override bool IsValid(object value)
    {
        return true;
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(
        ModelMetadata metadata, ControllerContext context)
    {
        var rule = new ModelClientValidationRule
        {
            ErrorMessage = ErrorMessage,
            ValidationType = "mycustomvalidator",
        };

        var viewContext = (ViewContext)context;
        var dependentProperty1 = viewContext.ViewData.TemplateInfo
            .GetFullHtmlFieldId("DependentProperty1");
        //var prefix = viewContext.ViewData.TemplateInfo.HtmlFieldPrefix;

        rule.ValidationParameters.Add("dependentproperty1", dependentProperty1);

        yield return rule;
    }
}

When executed on the client, the server attribute is ignored, and vice versa.

If you need to have a validation attribute on the class, chances are the validation happens against multiple fields. I dropped in some boilerplate code for passing additional parameters to the client validation method, but it's not working as I expected. In my actual code I have commented out the viewContext and dependentProperty1 vars, and just passed a "DependentProperty1" string to the second argument of the rule.ValidationParameters.Add method. For some reason, I'm getting an incorrect HtmlFieldPrefix. If anyone can help with this please comment...

Anyway, you end up with a viewmodel like this:

[MyCustomServerValidation(ErrorMessage = MyCustomValidationMessage)]
public class MyCustomViewModel
{
    private const string MyCustomValidationMessage = "user error!";

    [Display(Name = "Email Address")]
    [MyCustomClientValidation(ErrorMessage = MyCustomValidationMessage)]
    public string Value { get; set; }

    [HiddenInput(DisplayValue = false)]
    public string DependentProperty1 { get; set; }
}

A client script like this:

/// <reference path="jquery-1.6.2.js" />
/// <reference path="jquery.validate.js" />
/// <reference path="jquery.validate.unobtrusive.js" />

$.validator.addMethod('mycustomvalidator', function (value, element, parameters) {
    var dependentProperty1 = $('#' + parameters['dependentproperty1']).val();
    // return true or false
});
$.validator.unobtrusive.adapters.add('mycustomvalidator', ['dependentproperty1'], 
    function (options) {
        options.rules['mycustomvalidator'] = {
            dependentproperty1: options.params['dependentproperty1']
        };
        options.messages['mycustomvalidator'] = options.message;
    }
);

And a view like this:

@Html.EditorFor(m => m.Value)
@Html.EditorFor(m => m.DependentProperty1)
@Html.ValidationMessageFor(m => m.Value)
@Html.ValidationMessageFor(m => m)

Then if you have client validation disabled, the @Html.ValidationMessageFor(m => m) is displayed instead of the one for the property.


Nope, it's not possible. Sorry.

0

精彩评论

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