2

我有一个实现的视图模型,IValidatableObject它包含一个字符串和另一个视图模型的集合,如下所示:

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

Others我的验证使用以下提供的合同根据不同的规则检查每个对象IValidatableObject

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

由于真实的复杂结构,MainViewModel我不得不创建一个自定义模型绑定器,它重新构建模型并将 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

好吧,看来我离得更近了一点。我现在可以IValidatableObject通过将以下内容添加到我的自定义模型绑定器来运行我的方法:

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

似乎Validator.TryValidateObject调用验证方法并将最后一个参数设置为true使其验证所有属性。但是,我现在坚持使用validationResults控制器,以便可以以有意义的方式使用它们。

4

2 回答 2

10

我应该已经意识到我可以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

于 2012-12-03T13:51:27.490 回答
2

Paul 的出色答案可以重构为通用的验证并转换为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)));
        }
    }
}
于 2014-03-26T05:26:33.373 回答