我在我的ASP.NET MVC应用程序中使用xVal,这在一般情况下很棒。在Steve Sanderson's blog post之后,我创建了一个DataAnnotationsValidationRunner来对属性对象进行服务器端验证。这适用于简单的类。例如人:
public static class DataAnnotationsValidationRunner
{
public static IEnumerable<ErrorInfo> GetErrors(object o)
{
return from prop in TypeDescriptor.GetProperties(o).Cast<PropertyDescriptor>()
from attribute in prop.Attributes.OfType<ValidationAttribute>()
where !attribute.IsValid(prop.GetValue(o))
select new ErrorInfo(prop.Name, attribute.FormatErrorMessage(string.Empty), o);
}
}
public class Person
{
[Required(ErrorMessage="Please enter your first name")]
public string FirstName { get; set; }
[Required(ErrorMessage = "Please enter your last name")]
public string LastName { get; set; }
}
但是,如果我向此人添加Address属性,并使用DataAnnotation属性标记Address类,则不会验证它们。例如
public class Person
{
[Required(ErrorMessage="Please enter your first name")]
public string FirstName { get; set; }
[Required(ErrorMessage = "Please enter your last name")]
public string LastName { get; set; }
public Address Address { get; set; }
}
public class Address
{
[Required(ErrorMessage="Please enter a street address")]
public string Street { get; set; }
public string StreetLine2 { get; set; }
[Required(ErrorMessage = "Please enter your city")]
public string City { get; set; }
[Required(ErrorMessage = "Please enter your state")]
public string State { get; set; }
[Required(ErrorMessage = "Please enter your zip code")]
public string Zip { get; set; }
public string Country { get; set; }
}
一个问题是DataAnnotationValidationRunner不会向下走复杂的子属性。此外,如果将这些错误添加到错误集合中,则在添加到模型状态时仍需要正确添加前缀。例如。 Person错误添加如下:
catch (RulesException ex)
{
ex.AddModelStateErrors(ModelState, "person");
}
我认为地址规则例外需要以“person.address”作为前缀。是否支持使用xVal处理子对象验证的方法,或者创建扁平数据传输对象是否是唯一的解决方案?
答案 0 :(得分:2)
首先,您需要区分Steve Sanderson的DataAnnotationsModelBinder和
关于您的第一个问题(“DataAnnotationValidationRunner不会走下复杂的子属性”):
你可能是指Brad Wilson的DataAnnotationModelBinder吗?如果是这样,它确实应该将复杂的ViewModel验证到最后的属性。如果没有,请尝试使用它而不是您正在使用的DataAnnoationsModelRunner。这篇关于Client-Side Validation with xVal的博客文章博客文章展示了如何做。
DataAnnotationModelBinder的第一个版本有一个错误,当它与复杂的视图模型一起使用时会崩溃。也许有一个新版本可以修复崩溃,但忽略了复杂的模型?
在任何情况下,我都建议在上面链接的博客文章的演示项目中使用DataAnnotationModelBinder的版本。我在我自己的实际项目中使用它,它确实适用于复杂的视图模型。
关于您的第二个问题“是否支持使用xVal处理子对象验证的方法”:
您尚未发布任何驻留在ASPX表单上的代码,但您可能也指的是&lt;%= Html.ClientSideValidation()%&gt;仅将客户端验证添加到该模型类型的直接属性,但不添加子对象的属性。您可以使用多个ClientSideValidation语句来解决问题,例如:
<%= Html.ClientSideValidation<ModelType>()%>
<%= Html.ClientSideValidation<ChildModelType>("ChildModelPropertyName")%>
答案 1 :(得分:1)
我遇到了同样的问题。我需要验证可以作为另一个对象的属性出现的复杂对象。我还没有进入客户端验证(但是),但Adrian Grigore关于多个html.ClientSideValidation()的想法似乎可能就是那里的票。
我最终创建了一个标记界面,标记了我需要验证的所有类。它可以是一个属性,也可以将此想法用于类的所有属性。
基本上,它使用您在上面提到的DataAnnotationsValidationRunner验证对象,然后迭代对象的属性并对所有这些属性运行DataAnnotationsValicationRunner,直到无法检查为止。
这是我所做的伪代码:
IEnumarable<ValidationError> GetErrors(object instance) {
List<ValidationError> errors = new List<ValidationError>();
errors.AddRange(GetDataAnnotationErrors(instance));
errors.AddRange(GetPropertyErrors(instance));
return errors;
}
IEnumerable<ValidationError> GetDataAnnotationErrors(object instance) {
// code very similar to what you have above
}
IEnumearable<ValidationError> GetPropertyErrors(object instance)
{
var errors = new List<ValidationError>();
var objectsToValidate = instance.GetType().GetProperties().Where(p => p.PropertyType.GetInterface().Contains(typeof(IMarkerInterface)));
// the call above could do any type of reflecting over the properties you want
// could just check to make sure it isn't a base type so that all custom
// object would be checked
if(objectsToValidate == null) return errors;
foreach(object obj in objectsToValidate)
{
errors.AddRange(GetDataAnnotationErrors(obj));
errors.AddRange(GetPropertyErrors(obj));
}
return errors;
}
我希望这很清楚。我一直在域对象上测试这个系统,到目前为止一直很好。在这里和那里解决一些问题,但这个想法已经证明了我正在做的事情。