Аннотации данных для проверки, хотя бы одно обязательное поле? - PullRequest
29 голосов
/ 26 апреля 2010

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

Ответы [ 4 ]

23 голосов
/ 17 октября 2014

Я расширил ответ Zhaph для поддержки группировки свойств.

[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; }
}
22 голосов
/ 26 апреля 2010

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

Обратите внимание, что для этого вам нужно будет использовать 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, по вашему мнению.

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

1 голос
/ 11 мая 2016

Этот вопрос довольно старый, но начиная с .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" });
}
0 голосов
/ 26 апреля 2010

Если вы хотите провести комплексную проверку по любому классу .Net, не помечая их аннотациями, посмотрите FluentValidation или .Net 2.0, FluentValidation для 2.0

...