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

时间:2010-04-26 10:00:06

标签: asp.net asp.net-mvc validation asp.net-mvc-2 data-annotations

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

4 个答案:

答案 0 :(得分:22)

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

请注意,为了实现此目的,您需要使用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;
  }
}

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

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

然后,当您致电ModelState.IsValid时,系统会调用您的验证工具,您的信息将被添加到您视图的ValidationSummary中。

请注意,您可以对此进行扩展以检查返回的属性类型,或者如果您愿意,可以在其上查找属性以包含/排除验证 - 这假设一个通用验证器不知道任何有关输入它验证。

答案 1 :(得分:22)

我已经扩展了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;
    }
}

用法:

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

如果你想拥有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; }
}

答案 2 :(得分:1)

这个问题很老了,但是从.NET 3.5开始(我相信),IValidatableObject可以帮助解决棘手的验证问题。您可以实现它来验证任意业务规则。在这种情况下,例如:

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
    if (string.IsNullOrWhiteSpace(FieldOne) && string.IsNullOrWhiteSpace(FieldTwo))
        yield return new ValidationResult("Must provide value for either FieldOne or FieldTwo.", new string[] { "FieldOne", "FieldTwo" });
}

答案 3 :(得分:0)

如果您想针对任何.Net类进行复杂的验证,而不需要使用注释,请查看FluentValidation或.Net 2.0,FluentValidation for 2.0