【问题标题】:ASP.Net MVC 2 Controller's TryValidate doesn't validate the List<> items within the modelASP.Net MVC 2 控制器的 TryValidate 不验证模型中的 List<> 项
【发布时间】:2012-11-22 22:05:38
【问题描述】:

如何获得模型的验证以同时验证通用列表属性中的子对象。

我有一个模型,我正在尝试验证,这不是发布到服务器的内容,而是发布的一些信息的组合,以及服务器上已经存在的信息......例如。

 ...
public class A {
   [Required]
   public string Property1 { get; set; }
}
...
public class B {
   public List<A> Values { get; set; }
}
...
    if (!TryValidateModel(instanceofB))
    {
        //this should fire, as one of A inside B isn't valid.
        return View(instanceofB);
    }

当我尝试验证 B 的模型实例时,它不会验证 Values 集合的验证属性。

【问题讨论】:

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


    【解决方案1】:

    TryValidateModel 方法只下降了一层,因此它只检查 B 类型的对象上的 Validation 属性,而不是其嵌套对象上的属性。解决此问题的一种方法是定义您自己的 ValidationAttribute 实现:

    public class ListValidationAttribute : ValidationAttribute
    {
        public override bool IsValid(object value)
        {
            IEnumerable enumerable = value as IEnumerable;
            // If the input object is not enumerable it's considered valid.
            if (enumerable == null)
            {
                return true;
            }
            foreach (object item in enumerable)
            {
                // Get all properties on the current item with at least one
                // ValidationAttribute defined.
                IEnumerable<PropertyInfo> properties = item.GetType().
                    GetProperties().Where(p => p.GetCustomAttributes(
                    typeof(ValidationAttribute), true).Count() > 0);
                foreach (PropertyInfo property in properties)
                {
                    // Validate each property.
                    IEnumerable<ValidationAttribute> validationAttributes =
                        property.GetCustomAttributes(typeof(ValidationAttribute),
                        true).Cast<ValidationAttribute>();
                    foreach (ValidationAttribute validationAttribute in
                        validationAttributes)
                    {
                        object propertyValue = property.GetValue(item, null);
                        if (!validationAttribute.IsValid(propertyValue))
                        {
                            // Return false if one value is found to be invalid.
                            return false;
                        }
                    }
                }
            }
            // If everything is valid, return true.
            return true;
        }
    }
    

    现在可以使用属性验证List&lt;A&gt;

    public class B
    {
        [ListValidation]
        public List<A> Values { get; set; }
    }
    

    我尚未彻底测试上述方法的性能,但如果在您的情况下证明是一个问题,另一种方法是使用辅助函数:

        if (!ValidateB(instanceofB))
        {
            //this should fire, as one of A inside B isn't valid.
            return View(instanceofB);
        }
    
    ...
    
    public bool ValidateB(B b)
    {
        foreach (A item in b.Values)
        {
            if (!TryValidateModel(item))
            {
                return false;
            }
        }
        return true; 
    }
    

    【讨论】:

    • 暂时将其标记为正确答案...理想情况下,希望让孩子们适当地标记模型状态错误,但现在手动处理孩子错误...
    • @Jeroen:你能告诉我你是怎么知道 TryValidateModel 只能在一个级别上工作而不是在子项上工作的事实吗?
    • @DavidS:使用类浏览器(Reflector,IL Spy)检查它。
    【解决方案2】:

    我有一个类似的问题,我通过完全避免调用 TryValidate 来解决这个问题。我调用 TryValidate 的原因是因为我需要对我的模型进行一些更改,然后进行验证。我最终为模型创建了一个接口,并将默认模型绑定器替换为能够识别该接口并调用我的方法的模型绑定器。这一切都发生在框架调用 validate 第一次(递归)之前。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-29
      • 2015-02-26
      相关资源
      最近更新 更多