通用列表属性上的必需属性

时间:2011-06-21 16:41:20

标签: asp.net-mvc validation model generic-list

是否可以将[Required]属性放入List<>属性?

我绑定到POST上的通用列表,并且想知道如果属性中有0项,我是否可以使ModelState.IsValid()失败?

4 个答案:

答案 0 :(得分:30)

Required属性添加到list-style属性并不能真正做到你想要的。如果列表未创建,则会抱怨,但如果列表中存在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动态创建输入元素。

答案 1 :(得分:23)

对于那些寻找极简主义例子的人:

[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的行为,因此无需明确编码。

答案 2 :(得分:4)

对于那些使用C#6.0(及以上)并且正在寻找单行的人:

[AttributeUsage(AttributeTargets.Property)]
public sealed class CannotBeEmptyAttribute : RequiredAttribute
{
    public override bool IsValid(object value) => (value as IEnumerable)?.GetEnumerator().MoveNext() ?? false;
}

答案 3 :(得分:2)

根据我的要求修改了@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; }