什么是ModelState.IsValid的作用?

56

当我执行一个创建方法时,我将我的对象绑定到参数中,然后检查ModelState是否有效,以便将其添加到数据库:

但是,当我需要在添加到数据库之前更改某些内容时(在更改它之前,ModelState可能无效,因此我必须这样做),为什么模型状态仍然无效。

这个函数到底检查了什么?

这是我的示例:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "EncaissementID,libelle,DateEncaissement,Montant,ProjetID,Description")] Encaissement encaissement) {
  encaissement.Montant = Convert.ToDecimal(encaissement.Montant);
  ViewBag.montant = encaissement.Montant;
  if (ModelState.IsValid) {
    db.Encaissements.Add(encaissement);
    db.SaveChanges();
    return RedirectToAction("Index", "Encaissement");
  };
  ViewBag.ProjetID = new SelectList(db.Projets, "ProjetId", "nomP");
  return View(encaissement);
}

你的模型上有任何必填属性吗?如果这些必填字段中有任何一个未被输入,那么该模型的状态将无效。 - monstertjie_za
所有必需的属性都已输入,但我的模型状态仍然无效! - KhaoulaAtallah
看一下我的回答,也许你的视图绑定到了不可为空的 int 或 datetime 类型,这也可能导致 ModelState 无效。 - monstertjie_za
4个回答

59

ModelState.IsValid表示从请求中正确绑定模型的传入值并且在模型绑定过程中是否有任何显式指定的验证规则被违反。

在您的示例中,正在绑定的模型属于类类型Encaissement。 验证规则是通过使用属性、逻辑和添加到IValidatableObjectValidate()方法中的错误来指定模型的 - 或者仅仅在操作方法的代码中进行指定。

如果值能够正确地绑定到模型,并且在此过程中没有违反任何验证规则,则IsValid属性将为true。

以下是如何在您的模型类上实现验证属性和IValidatableObject的示例:

public class Encaissement : IValidatableObject
{
    // A required attribute, validates that this value was submitted    
    [Required(ErrorMessage = "The Encaissment ID must be submitted")]
    public int EncaissementID { get; set; }

    public DateTime? DateEncaissement { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        var results = new List<ValidationResult>();

        // Validate the DateEncaissment
        if (!this.DateEncaissement.HasValue)
        {
            results.Add(new ValidationResult("The DateEncaissement must be set", new string[] { "DateEncaissement" });
        }

       return results;
    }
}

以下是一个示例,展示了如何在您的示例的操作方法中应用相同的验证规则:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "EncaissementID,libelle,DateEncaissement,Montant,ProjetID,Description")] Encaissement encaissement) {

  // Perform validation
  if (!encaissement.DateEncaissement.HasValue)
  {
      this.ModelState.AddModelError("DateEncaissement", "The DateEncaissement must be set");
  }

  encaissement.Montant = Convert.ToDecimal(encaissement.Montant);

  ViewBag.montant = encaissement.Montant;

  if (ModelState.IsValid) {

    db.Encaissements.Add(encaissement);
    db.SaveChanges();
    return RedirectToAction("Index", "Encaissement");

  };

  ViewBag.ProjetID = new SelectList(db.Projets, "ProjetId", "nomP");

  return View(encaissement);
}

需要记住的是,模型属性的值类型也将得到验证。例如,不能将字符串值分配给int属性。如果这样做,它将无法绑定,并且错误将添加到ModelState中。

在您的示例中,EncaissementID值无法接受一个"Hello"的值,这将导致添加模型验证错误并使IsValid为false。

出现上述任何原因(可能还有更多)都会导致模型状态的IsValid布尔值为false


谢谢,但还是有点模糊!例如,当我在我的模型中更改某些内容时,我需要将字符串转换为十进制,然后将其添加到数据库中... modelstate.isvalid检查传递给参数的模型而不是我的更新后的状态? - KhaoulaAtallah
1
Luke,你能解释一下为什么在ASP.NET Core 3.0中不再需要调用ModelState.IsValid吗?似乎模型验证会自动发生,即使在一些旧项目中,如ASP.NET Core 2.2等。谢谢! - SpiritBob

26

ModelState.IsValid基本上会告诉你,根据添加到模型属性的数据注释,你提交给服务器的数据是否存在任何问题。

例如,如果您有一个[Required(ErrorMessage = "Please fill")],并且当您将表单提交到服务器时该属性为空,ModelState 将无效。

ModelBinder 还为您检查了一些基本内容。例如,如果您有一个 BirthDate 日期选择器,并且此选择器绑定到的属性不是可空的DateTime类型,则如果您未填写日期,则 ModelState 也将无效。

这里这里是一些有用的帖子可供阅读。


4
你可以在这里找到关于ModelState及其用法的优秀文章。
具体来说,IsValid属性是一个快速检查ModelState.Errors中是否有任何字段验证错误的方法。如果你不确定导致Model在提交到控制器方法之前无效的原因,可以检查ModelState["Property"].Errors属性,它应该至少产生一个表单验证错误。
编辑:已使用@ChrisPratt的正确字典语法进行更新。

ModelState.Errors不存在!只有SerializeErrors和AddModelError。 - KhaoulaAtallah
4
这段内容的意思是:ModelState["Property"].Errors。换句话说,ModelState 是一种字典。您模型上发布的任何属性都将获得一个键。您必须在适当的属性上索引字典,以查看该属性的错误。如果您只是想弄清楚出错原因,请调试并在发布操作中的某个地方设置断点。然后,逐个检查 ModelState 的每个键,查看其中的 Errors 集合。 - Chris Pratt

0

这并不是最佳答案,但我通过在Visual Studio的调试器中逐步查看ModelState Values来找到错误所在:

screenshot

我猜想每个对于为什么他们的ModelState无效有疑问的人都可以通过在代码中设置断点、检查值并找到一个(或多个)无效值来受益。

这不是运行生产网站的最佳方式,但这是开发人员找出代码问题的方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接