【问题标题】:Required Attribute on Generic List Property通用列表属性的必需属性
【发布时间】:2011-06-21 16:41:19
【问题描述】:

是否可以将 [Required] 属性放在 List 属性上?

我在 POST 上绑定到一个通用列表,想知道如果属性中有 0 个项目,我是否可以让 ModelState.IsValid() 失败?

【问题讨论】:

  • 如果您将模型更改为使用数组而不是列表,您可以使用MinLengthAttribute

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


【解决方案1】:

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。如果这就是您的视图的工作方式,您的属性需要变得更复杂一些,例如使用反射来提取泛型类型参数并将每个列表元素与default(T) 或其他内容进行比较。

更好的选择是使用 jQuery 动态创建输入元素。

【讨论】:

  • 我不认为你可以elaborate on that edit
  • 我不确定你要问的是什么编辑......你的链接只是一个问题。
  • 是的,这个问题(可能——这部分是我要问的)相关。
【解决方案2】:

对于那些正在寻找极简主义示例的人:

[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 继承行为,因此无需显式编码。

【讨论】:

  • 最通用的解决方案,谢谢!
  • 智能回答但对前端验证不友好
  • 一项改进是同时调用base.IsValid(value),以便保持基类行为。对于 C# 8 的用户,这可以像 return base.IsValid(value) &amp;&amp; value is IEnumerable seq &amp;&amp; seq.GetEnumerator().MoveNext(); 一样简单
【解决方案3】:

对于那些使用 C# 6.0(及更高版本)并且正在寻找单行代码的人:

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

【讨论】:

  • 你是说五线? :-)
【解决方案4】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-27
    • 1970-01-01
    • 2011-03-01
    • 2012-08-31
    • 1970-01-01
    • 2019-11-30
    相关资源
    最近更新 更多