2009-09-02 76 views
1

我在我的ASP.NET MVC应用程序中使用了xVal,这是非常棒的。在Steve Sanderson's blog post之后,我创建了一个DataAnnotationsValidationRunner来对属性对象进行服务器端验证。这对于一个简单的课程非常有用。例如联系人:xVal如何验证复杂类型的子属性?

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

不过,如果我添加一个地址属性给这个人,并标注地址类DataAnnotation属性,他们不会进行验证。例如

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并未沿着复杂的子属性行走。此外,如果将这些错误添加到错误集合中,则在添加到模型状态时仍然需要正确加前缀。例如。该人错误添加这样的:

catch (RulesException ex) 
    { 
     ex.AddModelStateErrors(ModelState, "person"); 
    } 

我想地址规则的例外是需要用“person.address”前缀。是否有支持使用xVal处理子对象验证的方法,或者创建平面数据传输对象是唯一的解决方案?

回答

2

首先,你需要史蒂夫·桑德森DataAnnotationsModelBinder和

关于你提到的第一个问题之间的不同(“DataAnnotationValidationRunner不走复杂的子属性”):

你也许是指Brad Wilson的DataAnnotationModelBinder?如果是这样,它确实应该复杂的ViewModel到最后的属性。如果没有,请尝试使用它而不是您正在使用的DataAnnoationsModelRunner。这篇博客文章博客文章Client-Side Validation with xVal显示了如何。

DataAnnotationModelBinder的第一个版本有一个错误,它会在与复杂的视图模型一起使用时崩溃。也许有一个新版本修复了崩溃但忽略了复杂的模型?

在任何情况下,我都会建议在上面链接的博客文章的演示项目中使用DataAnnotationModelBinder的版本。我在我自己的实际项目中使用它,它可以在复杂的视图模型上工作。

关于你提到的第二个问题:“有没有处理子对象的验证与XVAL支持的方式”:您还没有发布驻留在ASPX形式中的任何代码

,但你也可能指的是事实,那么<%= Html.ClientSideValidation()%>仅将客户端验证添加到该模型类型的即时属性,但不添加子对象的属性。你可以简单地通过使用多个ClientSideValidation语句,例如绕过这个问题:

<%= Html.ClientSideValidation<ModelType>()%> 
<%= Html.ClientSideValidation<ChildModelType>("ChildModelPropertyName")%> 
+0

第二个答案确实起作用,但如果父对象上有多个属性都关联了相同的子类型,但具有不同的属性,则会失败。即。 用户 帐单地址 ShippingAddress 看起来好像您可以调整xval.jquery验证实用程序来解决此问题。 – 2010-02-21 17:59:55

1

我有同样的问题。我需要验证可以作为另一个对象的属性出现的复杂对象。我还没有进入客户端验证(但),但从阿德里安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; 
} 

我希望这是显而易见的。我一直在域对象上测试这个系统,所以这么好。在这里和那里找出几个问题,但这个想法已经证明了我正在做的事情。