开发者

C# MVC using multiple atrributes with the OR condition

My goal is to create a validated IP address field that will be validated against an IP address regular express or an dynamic DNS address. So basically if the user enters an valid IP address OR a valid dynamic DNS address the client will allow it to go through. I have found articles showing how to make custom fields and how to multiple attributes on a data field but nothing about how to run them as an OR condition.

Here is my code for the custom IP and Domain Name attributes:

    public class IPAddressAttribute : RegularExpressionAttribute
    {
        public IPAddressAttribute()
            : base(@"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1开发者_如何学JAVA[0-9]{2}|2[0-4][0-9]|25[0-5])$")
        { }
    }
    public class DomainNameAttribute : RegularExpressionAttribute
    {
        public DomainNameAttribute()
            : base(@"^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$")
        { }
    }

And here is my code for the field:

[Required(ErrorMessage="Wan IP is required")]
[DisplayName("Wan IP")]
[IPAddress(ErrorMessage="Enter a valid IP")]
[DomainName(ErrorMessage="Enter a valid Domain Name")]
public virtual string wan_ip { get; set; }

This code currently checks on both attributes. When I enter a valid IP address it comes back saying that I need to enter in a valid domain name, which is understandable because it's trying to validate on both of the attributes. Because they are mutually exclusive they can never both be satisfied.

Any suggestions will be greatly appreciated!

Thanks!

Matthew


I'm pretty sure you would have to merge them into a single Attribute, something like

[DomainOrIPAddress]

And handle your OR logic within the attribute.

Or you could look into custom Model Validators


You could create a custom validation attribute, and use the two existing ones inside it. There's an article on MSDN on creating custom attributes.

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
sealed public class CustomAttribute : ValidationAttribute
{
    public override bool IsValid(object value)
    {
        IPAddressAttribute a1 = new IPAddressAttribute();
        DomainNameAttribute a2 = new DomainNameAttribute();
        return a1.IsValid(value) || a2.IsValid(value);
    }    
}


Using the strategy that Jason suggested, you could also create a more generic attribute to handle the "Or" logic. The best way I've found to do this is to receive the Type of the two attributes and then activate them internally (since you have strong argument constraints on the attributes).

Usage:

[OneOfAttribute(typeof(IPAddressAttribute), typeof(DomainNameAttribute), ...)]

Implementation:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public sealed class OneOfAttribute : ValidationAttribute
{
    public ValidationAttribute[] Validators { get; set; }

    public OneOfAttribute(params Type[] validatorTypes)
    {
        Validators = validatorTypes.Select(Activator.CreateInstance)
            .OfType<ValidationAttribute>()
            .ToArray();

        // just to make sure this was correctly invoked
        if (validatorTypes.Length != Validators.Length)
        {
            throw new ArgumentException("Invalid validation attribute type");
        }
    }

    public override bool IsValid(object value)
    {
        return Validators.Any(v => v.IsValid(value));
    }
}

Using this strategy you could also make this even more flexible, adding an argument to specify the type of the logical operation (OR, AND, etc) that will the used on the IsValid method.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜