ASP.Net MVC 2 Controller's TryValidate doesn't validate the List<> items within the model

倾然丶 夕夏残阳落幕 提交于 2019-11-27 07:11:21

问题


How do you get a model's validation to also validate child objects in a generic list property.

I have a model that I'm trying to validate, this is not what's being posted to the server, but a composite of some information posted, and information already on the server... for example.

 ...
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);
    }

When I try to validate the model instance of B, it won't validate the Values collection for their validation attributes.


回答1:


The TryValidateModel method only goes down one level so it only checks for Validation attributes on the object of type B, not on its nested objects. One way to overcome this is to define your own implementation of a 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;
    }
}

Now List<A> can be validated using the attribute:

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

I haven't tested performance for the above approach thoroughly but if in your case that turns out to be a problem, an alternative approach is to use a helper function:

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



回答2:


I had a similar issue that I fixed by avoiding the call to TryValidate altogether. The reason I called TryValidate was because I needed to do make some changes on my model and then do the validation. I ended up creating an interface for the model and replaced the default model binder with one that recognizes the interface and calls my method. This all happens before the framework calls validate the first time (which is recursive).



来源:https://stackoverflow.com/questions/4465432/asp-net-mvc-2-controllers-tryvalidate-doesnt-validate-the-list-items-within

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!