Массив должен содержать 1 элемент

У меня есть следующий класс:

public class CreateJob
{
    [Required]
    public int JobTypeId { get; set; }
    public string RequestedBy { get; set; }
    public JobTask[] TaskDescriptions { get; set; }
}

Я хотел бы иметь аннотацию данных выше TaskDescriptions так что массив должен содержать хотя бы один элемент? Так же, как [Required], Это возможно?

9 ответов

Решение

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

(Я привел пример со списком, но может быть адаптирован для массива или вы можете использовать список)

public class MustHaveOneElementAttribute : ValidationAttribute
{
    public override bool IsValid(object value)
    {
        var list = value as IList;
        if (list != null)
        {
            return list.Count > 0;
        }
        return false;
    }
}
[MustHaveOneElementAttribute (ErrorMessage = "At least a task is required")]
public List<Person> TaskDescriptions { get; private set; }

Это можно сделать с помощью стандартного атрибута валидации MinLengthAttribute, но работает ТОЛЬКО для массивов:

public class CreateJob
{
    [Required]
    public int JobTypeId { get; set; }
    public string RequestedBy { get; set; }
    [MinLength(1)]
    public JobTask[] TaskDescriptions { get; set; }
}

Вот немного улучшенная версия решения @dove, которое обрабатывает различные типы коллекций, такие как HashSet, List и т. Д.

public class MustHaveOneElementAttribute : ValidationAttribute
{
    public override bool IsValid(object value)
    {
        var collection = value as IEnumerable;
        if (collection != null && collection.GetEnumerator().MoveNext())
        {
            return true;
        }
        return false;
    }
}

Пожалуйста, позвольте мне добавить примечание об использовании MinLengthAttribute с.NET Core.

Microsoft рекомендует использовать Razor Pages, начиная с.NET Core 2.0.

В настоящее время проверка с помощью MinLengthAttribute для свойства в PageModel не работает:

[BindProperty]
[Required]
[MinLength(1)]
public IEnumerable<int> SelectedStores { get; set; }

ModelState.IsValid возвращает true, когда SelectedStores.Count() == 0.

Протестировано с.NET Core 2.1 Preview 2.

Вы должны использовать 2 стандартных атрибута аннотации

public class CreateJob
{
    [MaxLength(1), MinLength(1)]
    public JobTask[] TaskDescriptions { get; set; }
}

Начиная с .net 8, вы можете использовать System.ComponentModel.DataAnnotations.LengthAttribute.

Этот атрибут теперь работает сStringИCollection. Затем вы указываете минимальную и максимальную длину атрибута.

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

      [Length(1, int.MaxValue)]
public IEnumerable<int> TaskDescriptions { get; set; }

В дополнение к ответу mynkow я добавил возможность передавать атрибуту минимальное значение счетчика и создавать значимые сообщения об ошибках:

public class MinimumElementsRequiredAttribute : ValidationAttribute
{
  private readonly int _requiredElements;

  public MinimumElementsRequiredAttribute(int requiredElements)
  {
    if (requiredElements < 1)
    {
      throw new ArgumentOutOfRangeException(nameof(requiredElements), "Minimum element count of 1 is required.");
    }

    _requiredElements = requiredElements;
  }

  protected override ValidationResult IsValid(object value, ValidationContext validationContext)
  {
    if (!(value is IEnumerable enumerable))
    {
      return new ValidationResult($"The {validationContext.DisplayName} field is required.");
    }

    int elementCount = 0;
    IEnumerator enumerator = enumerable.GetEnumerator();
    while (enumerator.MoveNext())
    {
      if (enumerator.Current != null && ++elementCount >= _requiredElements)
      {
        return ValidationResult.Success;
      }
    }

    return new ValidationResult($"At least {_requiredElements} elements are required for the {validationContext.DisplayName} field.");
  }
}

Используйте это так:

public class Dto
{
  [MinimumElementsRequired(2)]
  public IEnumerable<string> Values { get; set; }
}

Просто обновляю ответ Dove (@dove) на синтаксис C# 9:

          public class MustHaveOneElementAttribute : ValidationAttribute
    {
        public override bool IsValid(object value)
            => value is IList {Count: > 0};
    }

Атрибут MinLength считает значение допустимым, если оно равно нулю. Поэтому просто инициализируйте ваше свойство в модели как пустой массив, и оно будет работать.

MinLength(1, ErrorMessageResourceName = nameof(ValidationErrors.AtLeastOneSelected), ErrorMessageResourceType = typeof(ValidationErrors))]
int[] SelectedLanguages { get; set; } = new int[0];
Другие вопросы по тегам