C # MVC, используя несколько атрибутов с условием ИЛИ - PullRequest
1 голос
/ 22 июня 2011

Моя цель - создать поле с проверенным IP-адресом, которое будет проверяться по IP-адресу, обычному экспрессу или динамическому DNS-адресу. Таким образом, в основном, если пользователь вводит действительный IP-адрес ИЛИ действительный динамический DNS-адрес, клиент разрешит ему пройти. Я нашел статьи, показывающие, как создавать настраиваемые поля и как использовать несколько атрибутов в поле данных, но ничего не говорится о том, как запускать их как условие ИЛИ.

Вот мой код для пользовательских атрибутов IP и доменного имени:

    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[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])$")
        { }
    }

А вот мой код для поля:

[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; }

Этот код в настоящее время проверяет оба атрибута. Когда я ввожу действительный IP-адрес, он возвращается, говоря, что мне нужно ввести действительное доменное имя, что понятно, потому что он пытается проверить оба атрибута. Поскольку они взаимоисключающие, они никогда не могут быть удовлетворены.

Любые предложения будут с благодарностью!

Спасибо!

Мэтью

Ответы [ 3 ]

3 голосов
/ 22 июня 2011

Я почти уверен, что вам придется объединить их в один атрибут, что-то вроде

[DomainOrIPAddress]

И обрабатывать логику ИЛИ внутри атрибута.* Или вы можете посмотреть на Валидаторы пользовательских моделей

2 голосов
/ 22 июня 2011

Вы можете создать собственный атрибут проверки и использовать два существующих внутри него.На MSDN есть статья о создании пользовательских атрибутов.

[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);
    }    
}
0 голосов
/ 19 февраля 2014

Используя стратегию, предложенную Джейсоном, вы также можете создать более общий атрибут для обработки логики «или». Лучший способ, который я нашел, - это получить тип двух атрибутов и затем активировать их внутренне (поскольку у вас есть строгие ограничения аргументов для атрибутов).

Использование:

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

Реализация:

[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));
    }
}

Используя эту стратегию, вы также можете сделать ее еще более гибкой, добавив аргумент, указывающий тип логической операции (ИЛИ, И и т. Д.), Которая будет использоваться в методе IsValid.

...