用于验证的数据注释,至少一个必填字段?

Boo*_*oob 31 asp.net validation asp.net-mvc data-annotations asp.net-mvc-2

如果我有一个包含字段列表的搜索对象,我可以使用System.ComponentModel.DataAnnotations命名空间将其设置为验证搜索中至少有一个字段不为null或为空吗?即所有字段都是可选字段,但应始终输入至少一个字段.

Val*_*ile 25

我已经扩展了Zhaph的答案以支持属性分组.

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class AtLeastOnePropertyAttribute : ValidationAttribute
{
    private string[] PropertyList { get; set; }

    public AtLeastOnePropertyAttribute(params string[] propertyList)
    {
        this.PropertyList = propertyList;
    }

    //See http://stackoverflow.com/a/1365669
    public override object TypeId
    {
        get
        {
            return this;
        }
    }

    public override bool IsValid(object value)
    {
        PropertyInfo propertyInfo;
        foreach (string propertyName in PropertyList)
        {
            propertyInfo = value.GetType().GetProperty(propertyName);

            if (propertyInfo != null && propertyInfo.GetValue(value, null) != null)
            {
                return true;
            }
        }

        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

[AtLeastOneProperty("StringProp", "Id", "BoolProp", ErrorMessage="You must supply at least one value")]
public class SimpleTest
{
    public string StringProp { get; set; }
    public int? Id { get; set; }
    public bool? BoolProp { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

如果你想拥有2组(或更多):

[AtLeastOneProperty("StringProp", "Id", ErrorMessage="You must supply at least one value")]
[AtLeastOneProperty("BoolProp", "BoolPropNew", ErrorMessage="You must supply at least one value")]
public class SimpleTest
{
    public string StringProp { get; set; }
    public int? Id { get; set; }
    public bool? BoolProp { get; set; }
    public bool? BoolPropNew { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

  • 这很好 - 谢谢.值得一提的是,当所有属性级验证成功通过时,只会触发这样的类级别验证(即调用IsValid()). (3认同)

Zha*_*uid 23

我会为此创建一个自定义验证器 - 它不会给你客户端验证,只是服务器端.

请注意,要使其正常工作,您需要使用nullable类型,因为值类型将默认为0false:

首先创建一个新的验证器:

using System.ComponentModel.DataAnnotations;
using System.Reflection;

// This is a class-level attribute, doesn't make sense at the property level
[AttributeUsage(AttributeTargets.Class)]
public class AtLeastOnePropertyAttribute : ValidationAttribute
{
  // Have to override IsValid
  public override bool IsValid(object value)
  {
    //  Need to use reflection to get properties of "value"...
    var typeInfo = value.GetType();

    var propertyInfo = typeInfo.GetProperties();

    foreach (var property in propertyInfo)
    {
      if (null != property.GetValue(value, null))
      {
        // We've found a property with a value
        return true;
      }
    }

    // All properties were null.
    return false;
  }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以用这个来装饰你的模型:

[AtLeastOneProperty(ErrorMessage="You must supply at least one value")]
public class SimpleTest
{
    public string StringProp { get; set; }
    public int? Id { get; set; }
    public bool? BoolProp { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

然后,当您调用ModelState.IsValid验证器时,将调用您的验证器,并将您的消息添加到视图上的ValidationSummary中.

请注意,您可以扩展它以检查返回的属性类型,或者查找它们的属性以包含/排除验证(如果您愿意) - 这假设一个通用验证器不知道它验证的类型的任何内容.

  • @Boob你骗子. (3认同)
  • 这是一个很好的解决方案; 但我认为更有用的是允许在属性级别对属性进行分组...而不是说类的所有属性必须至少设置一个; 一个人可以有两个,三个相关的组,其中必须设置这些组中的至​​少一个值 (3认同)
  • 在这种情况下,我不确定Darin的解决方案是否"更好" - Boob询问"至少有一个不是空的字段列表",而不仅仅是两个 - 但是要么可以扩展到: .(达林)获取必须具有值的字段列表.2.(我的)在属性上有一些注释并检查它们 - 使你能够拥有不在"必需"组中的字段(如daveL建议的那样). (2认同)