通用列表属性的必需属性

发布于 2024-11-16 06:55:21 字数 121 浏览 1 评论 0原文

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

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

Is it possible to put a [Required] attribute onto a List<> property?

I bind to a generic list on POST and was wondering if I could make ModelState.IsValid() fail if the property has 0 items in it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

从来不烧饼 2024-11-23 06:55:21

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 绑定到如下所示的视图:

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

更好的替代方法是使用 jQuery 动态创建输入元素。

Adding the Required attribute to a list-style property doesn't really do what you want. The will complain if the list isn't created, but won't complain if the list exists with 0 item in it.

However, it should be easy enough to derive your own data annotations attribute and make it check the list for Count > 0. Something like this (not tested yet):

[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);
    }
}

EDIT:

You'll also have to be careful how you bind your list in your view. For example, if you bind a List<String> to a view like this:

<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" />

The MVC model binder will always put 5 elements in your list, all String.Empty. If this is how your View works, your attribute would need to get a bit more complex, such as using Reflection to pull the generic type parameter and comparing each list element with default(T) or something.

A better alternative is to use jQuery to create the input elements dynamically.

会傲 2024-11-23 06:55:21

对于那些正在寻找简约示例的人:

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

For those who're looking for minimalist examples:

[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();
    }
}

This is modified code from the accepted answer. It is suitable in the case from the question, and in even more cases, since IEnumerable is higher in System.Collections hierarchy. Additionally, it inherits behavior from RequiredAttribute, so no need in coding it explicitly.

猫卆 2024-11-23 06:55:21

对于那些使用 C# 6.0(及更高版本)并且正在寻找俏皮话的人:

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

For those that use C# 6.0 (and above) and who are looking for one-liners:

[AttributeUsage(AttributeTargets.Property)]
public sealed class CannotBeEmptyAttribute : RequiredAttribute
{
    public override bool IsValid(object value) => (value as IEnumerable)?.GetEnumerator().MoveNext() ?? false;
}
心房敞 2024-11-23 06:55:21

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

Modified @moudrick implementation for my requirement

Required Validation Attribute for List and checkbox List

[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();
    }
}

If you have checkbox list

[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;
    }
}

Here is my View Model

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

Usage

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

[CustomCheckBoxListRequiredAttribute(ErrorMessage = "Required.")]
public IEnumerable<CheckBoxViewModel> CheckBoxRequiredList { get; set; }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文