简体   繁体   中英

Custom validation attribute calling another validation attribute

I want to create a custom validation attribute that calls other validation attributes.

For example I want to create an attribute called PasswordValidationAttribute . I want it to decorate the property it is defined on with RequiredAttribute , RegularExpressionAttribute and StringLengthAttribute with various parameters defined (such as the regular expression for a password and a maximum and minimum string length).

I'm struggling on where to begin, ascertain how much work is involved and determine if it is at all possible. Once this attribute is applied to a property I would like it to process the ValidationMessageFor HtmlHelper correctly and do a serverside call. I'm hoping I don't need to redefine them (otherwise it will be too much work).

For .net 4 it could look like:

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public class MyValidationAttribute : ValidationAttribute
{
    private readonly bool isRequired;

    public string Regex { get; set; }

    public int StringLength { get; set; }

    public MyValidationAttribute(bool isRequired)
    {
        this.isRequired = isRequired;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var composedAttributes = ConstructAttributes().ToArray();
        if (composedAttributes.Length == 0) return ValidationResult.Success;

        var errorMsgBuilder = new StringBuilder();
        foreach (var attribute in composedAttributes)
        {
            var valRes = attribute.GetValidationResult(value, validationContext);
            if (valRes != null && !string.IsNullOrWhiteSpace(valRes.ErrorMessage))
                errorMsgBuilder.AppendLine(valRes.ErrorMessage);
        }
        var msg = errorMsgBuilder.ToString();
        if (string.IsNullOrWhiteSpace(msg))
            return ValidationResult.Success;
        return new ValidationResult(msg);
    }

    private IEnumerable<ValidationAttribute> ConstructAttributes()
    {
        if (isRequired)
            yield return new RequiredAttribute();
        if (Regex != null)
            yield return new RegularExpressionAttribute(Regex);
        if (StringLength > 0)
            yield return new StringLengthAttribute(StringLength);
    }
}

Usage:

[MyValidationAttribute(true, Regex = "[a-z]*", StringLength = 3)]
public string Name { get; set; }

In .net 3.5 there is a limitation, that you cannot dynamically construct the message value from underlying attributes ( at least I was not able get to through it ). You can set only one message per whole attribute.

Everything changed is inside method IsValid .

public override bool IsValid(object value)
{
    var composedAttributes = ConstructAttributes().ToArray();
    if (composedAttributes.Length == 0) return true;
    return composedAttributes.All(a => a.IsValid(value));
}

Note to ErrorMessage :

Return value of IsValid method of ValidationAttribute in .net 3.5 is not ValidationResult but bool . When I tried to set the ErrorMessage , I got the error that value can be set only once .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM