ASP.NET MVC3 TryValidateModel验证整个模型集合,而不仅仅是单个实例

时间:2011-01-25 20:04:05

标签: asp.net asp.net-mvc asp.net-mvc-3

我有一个采取模型列表的操作。我想一次单独验证每个模型与整个模型集合。我正在尝试使用TryValidateModel,但似乎如果我的任何一个模型无效,则所有模型都无效。我的表单显示5个SurveyResponseModels(一个包含两个必需字符串和两个整数的类)。如果我完全填写所有五个模型,我将获得validCount = 5。但是,如果五个模型中的任何一个不完整(因此验证失败),我得到的validCount为0. TryValidateModel的预期行为是什么?如果是这样,关于我如何一次验证这些的任何想法?

    [HttpPost]
    public ActionResult Create(IList<SurveyResponseModel> respondents)
    {
        int validCount = 0;

        foreach (SurveyResponseModel respondent in respondents)
        {
            if (TryValidateModel(respondent))
            {
                validCount++;
            }
        }
        ModelState.AddModelError("", validCount.ToString() + " respondents passed validation");
    }

4 个答案:

答案 0 :(得分:4)

查看代码,在我看来TryValidateModel将验证所提供对象给出的所有类型的模型,而不仅仅是该特定对象本身。此外,它返回ModelState.IsValid属性的当前值,以便一旦存在无效模型,TryValidateModel的所有调用都将返回false。如果你想做这样的事情,我认为你需要在特定的模型实例上自己获取并运行每个模型实例的验证器。

我还认为模型验证器已经在您手动调用它们时运行。您可以通过在循环之前查看ModelState.IsValid的值来检查此(对于无效模型)。如果它是假的,那么这意味着验证器是由模型绑定器运行的,这就是我认为的情况。

您可以在http://aspnet.codeplex.com/找到MVC的源代码。

答案 1 :(得分:4)

TryValidateModel()会添加验证错误列表。使用ModelState.Clear()删除以前的错误。除非使用[ValidateInput(false)]属性,否则验证将自动作为模型绑定过程的一部分进行。有关详细信息,请参阅https://stackoverflow.com/a/8581918/1238406

答案 2 :(得分:1)

我在另一篇文章中看到了这种行为。

要继续使用tvanfosson的建议,我建议你在foreach之前设置一个断点,并检查ModelState以查看错误是否已存在。它们可能是:DefaultModelBinder已经放置它们。然后我可以想到两种可能性:

  1. 错误被正确传递,以某种方式识别每个被投诉人(我不认为是这种情况)。在这种情况下,一个简单的linq表达式可以让您了解有问题的受访者。
  2. 错误是混合的,例如,如果2个受访者的名称无效,则名称只有一个错误,或者您无法区分哪个受访者。在这种情况下,您需要创建自定义验证逻辑。您可以创建一个像RespondentListViewModel这样的对象,并创建一个RespondentListViewModelBinder。您可以查看上面的源代码,了解DefautlModelBinder如何验证列表并添加模型错误。
  3. 是的,它是ASP.NET MVC的这一部分,其中绑定逻辑并不能完成我们想要它做的事情......

答案 3 :(得分:1)

源代码:

    protected internal bool TryValidateModel(object model, string prefix) {
        if (model == null) {
            throw new ArgumentNullException("model");
        }

        ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType());

        foreach (ModelValidationResult validationResult in ModelValidator.GetModelValidator(metadata, ControllerContext).Validate(null)) {
            ModelState.AddModelError(DefaultModelBinder.CreateSubPropertyName(prefix, validationResult.MemberName), validationResult.Message);
        }

        return ModelState.IsValid;
    }

如果错误,它将始终返回false。