2012-09-07 28 views
1

在我的項目中,我有一個使用另一個類的模型類,如下面的示例中所示。 模型中的一個屬性取決於對子對象屬性的驗證 - 在此示例中,LastName屬性取決於Address.PostalCode屬性值的驗證。 我實現了一個自定義驗證屬性來驗證我的姓氏屬性,它的效果很好。如何將複雜類綁定到視圖,同時保留我的自定義驗證屬性?

public class User 
{ 
    public static ValidationResult ValidateLastName(string lastName, ValidationContext context) 
    { 
     // Grab the model instance 
     var user = context.ObjectInstance as User; 
     if (user == null) 
      throw new NullReferenceException(); 

     // Cross-property validation 
     if (user.Address.postalCode.Length < 10000) 
      return new ValidationResult("my LastName custom validation message."); 

     return ValidationResult.Success; 
    } 

    [Display(Name = "Last name")] 
    [CustomValidationAttribute(typeof(User), "ValidateLastName")] 
    public string LastName { get; set; } 

    [Display(Name = "First name")] 
    public string FirstName { get; set; } 

    [Display(Name = "Address:")] 
    [CustomValidationAttribute(typeof(User), "ValidateAddress")] 
    public AddressType Address { get; set; } 
} 

public class AddressType 
{ 
    public string streetName = ""; 

    public string streetNumber = ""; 
    public string postalCode = ""; 
} 

問題是在控制器中,Address屬性沒有從視圖構造出來,而是始終爲空。 在這個示例中,無論我在視圖中發送什麼,user.Address都始終爲空。 這裏是控制器代碼。

[HttpPost] 
    public ActionResult Create(User user) 
    { 
     if (ModelState.IsValid) 
     { 
      // creation code here 
      return RedirectToAction("Index"); 
     } 
     else 
     { 
      return View(user); 
     } 
    } 

這裏是視圖:

 <div class="editor-label"> 
      @Html.LabelFor(model => model.Address.postalCode) 
     </div> 
     <div class="editor-field"> 
      @Html.EditorFor(model => model.Address.postalCode) 
      @Html.ValidationMessageFor(model => model.Address.postalCode) 
     </div> 

要解決這個問題,我創建了一個自定義的虛擬粘結劑在模型映射在視圖中的屬性字段,如下所示:

public class UserBinder : IModelBinder 
{ 
    private string GetValue(ModelBindingContext bindingContext, string key) 
    { 
     var result = bindingContext.ValueProvider.GetValue(key); 
     return (result == null) ? null : result.AttemptedValue; 
    } 

    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     User instance = new User(); 
     instance.FirstName = GetValue(bindingContext, "FirstName"); //controllerContext.HttpContext.Request["FirstName"]; 
     instance.LastName = GetValue(bindingContext, "LastName"); //controllerContext.HttpContext.Request["LastName"]; 

     instance.Address = new AddressType(); 
     string streetName = controllerContext.HttpContext.Request["Address.streetName"]; 

     //ModelStateDictionary mState = bindingContext.ModelState; 
     //mState.Add("LastName", new ModelState { }); 
     //mState.AddModelError("LastName", "There's an error."); 

     instance.Address.streetName = streetName; 
        ... 
     return instance; 
    } 

活頁夾工作正常,但驗證屬性不再有效。 我認爲必須有一個更好的方式來做綁定比這個,是嗎?

這個活頁夾只是將LastName映射到LastName和Address.streetName到Address.streetName,我想應該有一種方法可以完成這個任務,而不必編寫所有這些繁瑣的代碼,而且不會破壞自定義驗證機制。

回答

1

一種解決方案是在我的子類,而不是使用公共領域的特性 - 由於俄德的答案!

另一種解決方案是在控制器中調用TryValidateModel,這使得我的驗證代碼即使在活頁夾存在的情況下也是如此。

[HttpPost] 
    public ActionResult Create(User user) 
    { 
     if (TryValidateModel(user)) 
     { 
      // creation code here 
      return RedirectToAction("Index"); 
     } 
     else 
     { 
      return View(user); 
     } 
    } 
2

爲了使默認模型綁定正常工作,您需要使用屬性而不是公用字段。

AddressType類更改:

public class AddressType 
{ 
    public string streetName { get; set; } 
    public string streetNumber { get; set; } 
    public string postalCode { get; set; } 
} 
+0

那工作,謝謝!這意味着我畢竟不需要自定義聯編程序。 – Ian

+0

@Ian - 很高興能幫到你。 – Oded

相關問題