TryValidate контроллера ASP.Net MVC 2 не проверяет элементы List<> в модели
Как вы получаете проверку модели, чтобы также проверить дочерние объекты в универсальном свойстве списка.
У меня есть модель, которую я пытаюсь проверить, это не то, что публикуется на сервере, а совокупность некоторой размещенной информации и информации, уже находящейся на сервере... например.
...
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, он не будет проверять коллекцию значений для их атрибутов проверки.
2 ответа
TryValidateModel
метод идет только вниз на один уровень, поэтому он проверяет только Validation
атрибуты на объекте типа B
, а не на вложенных объектах. Одним из способов преодоления этого является определение собственной реализации 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<A>
может быть проверено с помощью атрибута:
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;
}
У меня была похожая проблема, которую я исправил, вообще избежав вызова TryValidate. Причина, по которой я позвонил в TryValidate, заключалась в том, что мне нужно было внести некоторые изменения в мою модель, а затем выполнить проверку. В итоге я создал интерфейс для модели и заменил связыватель модели по умолчанию на тот, который распознает интерфейс и вызывает мой метод. Все это происходит до того, как вызовы фреймворка впервые выполнят валидацию (что является рекурсивным).