Обязательный атрибут в общем списке свойств - PullRequest
30 голосов
/ 21 июня 2011

Можно ли поместить атрибут [Required] в свойство List <>?

Я связался с универсальным списком на POST, и мне было интересно, смогу ли я вызвать сбой ModelState.IsValid (), если свойство содержит 0 элементов?

Ответы [ 4 ]

30 голосов
/ 21 июня 2011

Добавление атрибута Required к свойству стиля списка на самом деле не делает то, что вы хотите.Он будет жаловаться, если список не создан, но не будет жаловаться, если список существует с 0 элементами в нем.

Однако должно быть достаточно просто получить собственный атрибут аннотаций данных и заставить его проверить список на Count> 0. Что-то вроде этого (еще не проверено):

[AttributeUsage(AttributeTargets.Property)]
public sealed class CannotBeEmptyAttribute : ValidationAttribute
{
    private const string defaultError = "'{0}' must have at least one element.";
    public CannotBeEmptyAttribute ( ) : base(defaultError) //
    { 
    }

    public override bool IsValid ( object value )
    {
      IList list = value as IList;
      return ( list != null && list.Count > 0 );
    }

    public override string FormatErrorMessage ( string name )
    {
        return String.Format(this.ErrorMessageString, name);
    }
}

РЕДАКТИРОВАТЬ:

Вы также должны быть осторожны, как вы связываете свой список в вашем представлении.Например, если вы связываете List<String> с представлением, подобным этому:

<input name="ListName[0]" type="text" />
<input name="ListName[1]" type="text" />
<input name="ListName[2]" type="text" />
<input name="ListName[3]" type="text" />
<input name="ListName[4]" type="text" />

Связыватель модели MVC всегда помещает в ваш список 5 элементов, все String.Empty.Если именно так работает ваш View, ваш атрибут должен быть немного более сложным, например, используя Reflection для получения параметра универсального типа и сравнивая каждый элемент списка с default(T) или чем-то еще.

Лучшая альтернативаиспользовать jQuery для динамического создания элементов ввода.

23 голосов
/ 31 января 2014

Для тех, кто ищет минималистские примеры:

[AttributeUsage(AttributeTargets.Property)]
public sealed class CannotBeEmptyAttribute : RequiredAttribute
{
    public override bool IsValid(object value)
    {
        var list = value as IEnumerable;
        return list != null && list.GetEnumerator().MoveNext();
    }
}

Это модифицированный код из принятого ответа.Это подходит в случае с вопросом, а в еще большем числе случаев, поскольку IEnumerable выше в иерархии System.Collections.Кроме того, он наследует поведение от RequiredAttribute, поэтому нет необходимости явно его кодировать.

4 голосов
/ 21 декабря 2016

Для тех, кто использует C # 6.0 (и выше) и кто ищет однострочники:

[AttributeUsage(AttributeTargets.Property)]
public sealed class CannotBeEmptyAttribute : RequiredAttribute
{
    public override bool IsValid(object value) => (value as IEnumerable)?.GetEnumerator().MoveNext() ?? false;
}
2 голосов
/ 12 декабря 2015

Модифицированная реализация @moudrick для моего требования

Обязательный атрибут проверки для списка и списка флажков

[AttributeUsage(AttributeTargets.Property)]
public sealed class CustomListRequiredAttribute : RequiredAttribute
{
    public override bool IsValid(object value)
    {
        var list = value as IEnumerable;
        return list != null && list.GetEnumerator().MoveNext();
    }
}

Если у вас есть список флажков

[AttributeUsage(AttributeTargets.Property)]
public sealed class CustomCheckBoxListRequiredAttribute : RequiredAttribute
{
    public override bool IsValid(object value)
    {
        bool result = false;

        var list = value as IEnumerable<CheckBoxViewModel>;
        if (list != null && list.GetEnumerator().MoveNext())
        {
            foreach (var item in list)
            {
                if (item.Checked)
                {
                    result = true;
                    break;
                }
            }
        }

        return result;
    }
}

Вот мойПросмотр модели

public class CheckBoxViewModel
{        
    public string Name { get; set; }
    public bool Checked { get; set; }
}

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

[CustomListRequiredAttribute(ErrorMessage = "Required.")]
public IEnumerable<YourClass> YourClassList { get; set; }

[CustomCheckBoxListRequiredAttribute(ErrorMessage = "Required.")]
public IEnumerable<CheckBoxViewModel> CheckBoxRequiredList { get; set; }
...