2012-12-03 85 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))); 
     } 
    } 
}