【问题标题】:Skip all the validation of a model base on one of its property (ASP.Net Core 2.0)跳过基于模型属性之一的模型验证(ASP.Net Core 2.0)
【发布时间】:2018-02-17 16:33:46
【问题描述】:

如何跳过基于模型属性之一的模型验证。例如,如果对象的 WillBeDeleted 属性为 true,则验证器会跳过所有验证规则。

namespace ViewModel
{
    public class ContactForm : IViewModel
    {
        [ValidateNever]
        public Contact Item { get; set; }

        public Category Category { get; set; }

        [Required, DisplayName("First name")]
        [StringLength(200, ErrorMessage = "First name should not exceed 200 characters.")]
        public string FirstName { get; set; }

        [Required, DisplayName("Last name")]
        [StringLength(200, ErrorMessage = "Last name should not exceed 200 characters.")]
        public string LastName { get; set; }

        public List<TelephonesSubForm> Telephones { get; set; } = new List<TelephonesSubForm>();

        public List<EmailsSubForm> Emails { get; set; } = new List<EmailsSubForm>();

        public class TelephonesSubForm : IViewModel
        {
            public int Id { get; set; }

            public bool MustBeDeleted { get; set; }

            [Required]
            public TelephoneAndEmailType Type { get; set; }

            [Required]
            [StringLength(200, MinimumLength = 10, ErrorMessage = "Telephone should not exceed 200 characters.")]
            public string Telephone { get; set; }
        }

        public class EmailsSubForm
        {
            public int Id { get; set; }

            public bool MustBeDeleted { get; set; }

            [Required]
            public TelephoneAndEmailType Type { get; set; }

            [Required]
            [StringLength(200, MinimumLength = 10, ErrorMessage = "Email should not exceed 200 characters.")]
            public string Email { get; set; }
        }
    }
}

在给定的示例模型中,当MustBeDeletedtrue 时,表示电子邮件或电话项目将在保存操作中被删除。

我搜索并发现了几个关于条件(自定义)验证的问题,他们建议在检查其验证状态之前从ModelState 中删除特定键。喜欢this一个。

【问题讨论】:

    标签: c# asp.net asp.net-mvc validation asp.net-core


    【解决方案1】:

    我正在添加一个新答案并保留旧答案,因为它可能对某人有用

    所以,创建一个自定义属性:

      public class CustomShouldValidateAttribute : Attribute, IPropertyValidationFilter
      {
        public CustomShouldValidateAttribute(){
    
        }
        public bool ShouldValidateEntry(ValidationEntry entry, ValidationEntry parentEntry)
        {
          //Here you change this verification to Wether it should verificate or not, In this case we are checking if the property is ReadOnly (Only a get method)
          return !entry.Metadata.IsReadOnly;      
        }
      }
    

    他们在你的课堂上用你的自定义属性装饰它

    [CustomShouldValidateAttribute]
    public class MyClass{
    public string Stuff{get;set;}
    public string Name {get{return "Furlano";}}
    }
    

    【讨论】:

      【解决方案2】:

      虽然这不是问题的完整答案,但可以继承验证属性(RequiredAttributeStringLengthetc)并覆盖IsValid 方法。作为示例,我提供了其中一个。

      public class RequiredWhenItIsNotDeletingAttribute : RequiredAttribute
      {
          string DeletingProperty;
      
          /// <summary>
          /// Check if the object is going to be deleted skip the validation.
          /// </summary>
          /// <param name="deletingProperty">The boolean property which shows the object will be deleted.</param>
          public RequiredWhenItIsNotDeletingAttribute(string deletingProperty = "MustBeDeleted") =>
              DeletingProperty = deletingProperty;
      
          protected override ValidationResult IsValid(object value, ValidationContext validationContext)
          {
              var property = validationContext.ObjectType.GetProperty(DeletingProperty);
      
              if((bool)property.GetValue(validationContext.ObjectInstance))
                  return ValidationResult.Success;
      
              return base.IsValid(value, validationContext);
          }
      }
      

      【讨论】:

        【解决方案3】:

        从 IValidatableObject 继承你的模型

        并实现接口方法:

          public virtual IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
            {
        
              if (YourCondition==false){
                yield return new ValidationResult(
                  $"This is wrong",
                  new[] { nameof(Email) });
              }
              else
                 yield return ValidationResult.Success
        
            }
        

        但是你必须为你的每个属性实现一个验证,并排除你已经编写的装饰!

        【讨论】:

          【解决方案4】:

          你可以调用方法:

          ModelState.Clear()
          

          当 MustBeDeleted 为真时

          【讨论】:

          • 谢谢@EricImhauser,在问题的最后一段,我使用了一个包含您答案的链接。此外,如果我清除整个模型状态,所有验证都将被删除,而我需要避免与 TelephonesSubForm 或 EmailsS​​ubForm 之一相关的所有验证。
          • 从子表单中的 ModelState 中删除单个项目有什么问题?
          • 它有两个问题,首先,它会导致做更多的进程,这是无用的。验证并删除其结果。其次,最好用一个属性或类似的东西来解决解决方案,它为所有动作编码一次,而不是在所有动作中删除验证结果。
          • 它(其次,...)是我更喜欢其他答案的原因。
          猜你喜欢
          • 1970-01-01
          • 2017-03-09
          • 1970-01-01
          • 2019-04-24
          • 1970-01-01
          • 1970-01-01
          • 2019-08-09
          • 2011-02-16
          • 2017-12-14
          相关资源
          最近更新 更多