Подтвердить что ты не робот

Аннотации данных для проверки, по крайней мере, одного обязательного поля?

Если у меня есть объект поиска со списком полей, могу ли я, используя пространство имен System.ComponentModel.DataAnnotations, настроить его для проверки того, что хотя бы одно из полей поиска не является нулевым или пустым? i.e Все поля являются необязательными, но по крайней мере один должен всегда вводиться.

4b9b3361

Ответ 1

Я бы создал для этого специальный валидатор - он не даст вам проверку на стороне клиента, только на стороне сервера.

Обратите внимание, что для этого вам нужно будет использовать типы nullable, поскольку значения типов будут по умолчанию равны 0 или false:

Сначала создайте новый валидатор:

using System.ComponentModel.DataAnnotations;
using System.Reflection;

// This is a class-level attribute, doesn't make sense at the property level
[AttributeUsage(AttributeTargets.Class)]
public class AtLeastOnePropertyAttribute : ValidationAttribute
{
  // Have to override IsValid
  public override bool IsValid(object value)
  {
    //  Need to use reflection to get properties of "value"...
    var typeInfo = value.GetType();

    var propertyInfo = typeInfo.GetProperties();

    foreach (var property in propertyInfo)
    {
      if (null != property.GetValue(value, null))
      {
        // We've found a property with a value
        return true;
      }
    }

    // All properties were null.
    return false;
  }
}

Затем вы можете украсить свои модели следующим образом:

[AtLeastOneProperty(ErrorMessage="You must supply at least one value")]
public class SimpleTest
{
    public string StringProp { get; set; }
    public int? Id { get; set; }
    public bool? BoolProp { get; set; }
}

Затем, когда вы вызываете ModelState.IsValid, ваш валидатор будет вызван, и ваше сообщение будет добавлено в ValidationSummary в вашем представлении.

Обратите внимание, что вы можете расширить это, чтобы проверить, возвращается ли тип возвращаемого свойства, или искать атрибуты на них для включения/исключения из проверки, если вы хотите - это предполагает общий валидатор, который ничего не знает о введите его валидацию.

Ответ 2

Я продлил ответ Жафа, чтобы поддержать группировку свойств.

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class AtLeastOnePropertyAttribute : ValidationAttribute
{
    private string[] PropertyList { get; set; }

    public AtLeastOnePropertyAttribute(params string[] propertyList)
    {
        this.PropertyList = propertyList;
    }

    //See http://stackoverflow.com/a/1365669
    public override object TypeId
    {
        get
        {
            return this;
        }
    }

    public override bool IsValid(object value)
    {
        PropertyInfo propertyInfo;
        foreach (string propertyName in PropertyList)
        {
            propertyInfo = value.GetType().GetProperty(propertyName);

            if (propertyInfo != null && propertyInfo.GetValue(value, null) != null)
            {
                return true;
            }
        }

        return false;
    }
}

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

[AtLeastOneProperty("StringProp", "Id", "BoolProp", ErrorMessage="You must supply at least one value")]
public class SimpleTest
{
    public string StringProp { get; set; }
    public int? Id { get; set; }
    public bool? BoolProp { get; set; }
}

И если вы хотите иметь 2 группы (или более):

[AtLeastOneProperty("StringProp", "Id", ErrorMessage="You must supply at least one value")]
[AtLeastOneProperty("BoolProp", "BoolPropNew", ErrorMessage="You must supply at least one value")]
public class SimpleTest
{
    public string StringProp { get; set; }
    public int? Id { get; set; }
    public bool? BoolProp { get; set; }
    public bool? BoolPropNew { get; set; }
}

Ответ 3

Этот вопрос довольно старый, но с .NET 3.5 (я считаю) IValidatableObject может помочь в сложных ситуациях проверки. Вы можете реализовать его для проверки произвольных бизнес-правил. В этом случае что-то вроде:

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
    if (string.IsNullOrWhiteSpace(FieldOne) && string.IsNullOrWhiteSpace(FieldTwo))
        yield return new ValidationResult("Must provide value for either FieldOne or FieldTwo.", new string[] { "FieldOne", "FieldTwo" });
}

Ответ 4

Если вы хотите выполнить сложную валидацию в отношении любого .Net-класса, не указывая их аннотациями, посмотрите FluentValidation или на .Net 2.0, FluentValidation для 2.0