【问题标题】:Data Annotations for validation, at least one required field?用于验证的数据注释,至少一个必填字段?
【发布时间】:2011-02-12 08:10:14
【问题描述】:

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

【问题讨论】:

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


    【解决方案1】:

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

    【讨论】:

    • 这太好了 - 谢谢。值得一提的是,只有当所有属性级验证成功通过时,才会触发这样的类级验证(即调用 IsValid())。
    【解决方案2】:

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

    请注意,要使其正常工作,您需要使用 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 不错。我不知道可以使用 DataAnnotations 添加类级别属性。
    • 这看起来真的很不错,我会在本周末之前回复这个问题并给你答案。我会让你知道结果如何!谢谢
    • @JefClaes - 是的:答案在评论之前就被接受了,所以我们不知道它是否完全有效,我认为沉默是隐含的接受;)
    • 这是一个不错的解决方案;但我认为更有用的是允许在属性级别对属性进行分组......而不是说必须为类的所有属性设置至少一个;一个可能有两个、三个相关组,其中必须设置这些组中的至​​少一个值
    • 我不确定 Darin 的解决方案在这种情况下是否“更好” - Boob 询问“至少一个不为空的字段列表 [...]”,而不仅仅是两个 - 但是两者都可以扩展为: 1. (Darin) 获取必须具有值的字段列表。 2.(我的)在属性上有一些注释并检查它们 - 使您能够拥有不在“必需”组中的字段(正如 daveL 建议的那样)。
    【解决方案3】:

    这个问题已经很老了,但是从 .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" });
    }
    

    【讨论】:

      【解决方案4】:

      如果您想对任何 .Net 类进行复杂的验证,而不用注解,请查看 FluentValidation,或者对于 .Net 2.0,FluentValidation for 2.0

      【讨论】:

      • Daniel,感谢您的回答,但由于到目前为止我们在项目中一直在成功使用注释,并且它非常适合我们所需要的,我想尝试坚持这种方法验证。这是迄今为止第一个真正的绊脚石,我希望有人可以为我提供一个很好的解决方案! :)
      • 不用担心。当您有时间时,请查看链接。您会发现 Fluent 方法直观且易于使用。而且非常强大。
      • 这真的是基于意见的:)
      • 嗨@zaitsman 你是说“乱扔垃圾”这个词吗?也许你是对的。我的答案是将近 8 年前写的。 :) 即使经过这么长时间,我发现注入 FluentValidation abstractvalidator 的派生词更容易。特别是在对缓存的集合或存储库查找进行复杂验证时
      【解决方案5】:

      .net 中的验证检查属性。假设您有两个字符串属性,field1 和 field2。只需添加这样的属性。

      [RegularExpression("True|true", ErrorMessage = "At least one field must be given a value")] 
      public bool Any => field1 != null || field2 != null;
      

      此处有详细信息,以及 MinLength 等附加验证:https://stackoverflow.com/a/69621414/6742644

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-01-05
        • 1970-01-01
        • 2017-02-07
        • 2013-03-25
        • 1970-01-01
        • 2011-07-21
        • 1970-01-01
        相关资源
        最近更新 更多