2012-12-03 82 views
2

我有一個實現IValidatableObject包含字符串,另一個視圖模型的集合,像這樣一個視圖模型:驗證視圖模型後,定製模型綁定

public sealed class MainViewModel 
{ 
    public string Name { get; set; } 
    public ICollection<OtherViewModel> Others { get; set; } 
} 

我的驗證檢查在Others每個對象對

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) 
{ 
    foreach (var other in this.Others) 
    { 
     // validate or yield return new ValidationResult 
    } 
} 

因爲真正MainViewModel我不得不創造出一個自定義的模型綁定的複雜結構的重新構建男:利用IValidatableObject提供的合同不同的規則odel並將POST數據分配給相關組件。那我得到的問題是,什麼是越來越驗證導致在上下文級的驗證錯誤,因爲它違反了某些數據庫約束和我不知道我做錯了什麼 - 我認爲ModelState.IsValid將在調用Validate方法我的觀點模型,但似乎並沒有這樣下去。

我的模型綁定看起來是這樣的:

public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
{ 
    int modelId = (int)controllerContext.RouteData.Values["id"]; 

    // query the database and re-build the components of the view model 

    // iterate the POST data and assign to the model where necessary 

    // should I be calling something here to validate the model before it's passed to the controller? 

    return model; 
} 

任何幫助表示讚賞!

Validator.TryValidateObject

OK,看來我有點接近。現在我可以讓我IValidatableObject方法通過向運行以下命令以我的自定義模型綁定:

var validationResults = new HashSet<ValidationResult>(); 
var isValid = Validator.TryValidateObject(model, new ValidationContext(model, null, null), validationResults, true); 

似乎Validator.TryValidateObject調用驗證方法,最後一個參數設置爲true導致它來驗證所有屬性。但是,我現在堅持要將validationResults交給控制器,以便它們能夠以有意義的方式使用。

回答

8

我應該已經意識到,我可以通過自定義粘結劑使用ModelState.AddModelError,我已經成功地得到這個工作現在正確地模型返回到控制器之前添加以下到我的自定義模型粘合劑:

var validationResults = new HashSet<ValidationResult>(); 
var isValid = Validator.TryValidateObject(model, new ValidationContext(model, null, null), validationResults, true); 
if (!isValid) 
{ 
    foreach (var result in validationResults) 
    { 
     bindingContext.ModelState.AddModelError("", result.ErrorMessage); 
    } 
} 

return model; 

現在,這將返回所有錯誤,我的網頁和ModelState.IsValid檢查我的控制器操作現在返回false的列表。

+0

其中我需要將此代碼放在:控制器和操作以及模型聯編程序和其中?其實我得到這個錯誤,請幫助。 – Rajpurohit

+2

@Rajpurohit你會把上面的代碼放到你的自定義模型聯編程序類中。 –

+0

其實我已經這樣做了,但是感謝@保羅。 - :) – Rajpurohit

2

保羅的偉大答案可以重構爲通用驗證並轉換爲ModelState方法,如下所示(例如,在助手或CustomModelBinder基礎中)。另外,保留了對已驗證屬性的綁定。

public static void DoValidation(ModelBindingContext bindingContext, 
           IValidatableObject model) 
{ 
    var validationResults = new HashSet<ValidationResult>(); 
    var isValid = Validator.TryValidateObject(model, 
     new ValidationContext(model, null, null), validationResults, true); 
    if (!isValid) 
    { 
     var resultsGroupedByMembers = validationResults 
      .SelectMany(_ => _.MemberNames.Select(
       x => new {MemberName = x ?? "", 
          Error = _.ErrorMessage})) 
      .GroupBy(_ => _.MemberName); 

     foreach (var member in resultsGroupedByMembers) 
     { 
      bindingContext.ModelState.AddModelError(
       member.Key, 
       string.Join(". ", member.Select(_ => _.Error))); 
     } 
    } 
}