2009-09-02 61 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; 
} 

我希望這是顯而易見的。我一直在域對象上測試這個系統,所以這麼好。在這裏和那裏找出幾個問題,但這個想法已經證明了我正在做的事情。