【问题标题】:MVC Check model values in form using TryUpdateModel in ControllerMVC 使用 Controller 中的 TryUpdateModel 检查表单中的模型值
【发布时间】:2016-11-10 16:33:42
【问题描述】:

我目前正在学习有关 MVC 5 的教程,但我一直在思考如何在不绑定编辑方法中的字段的情况下对用户输入的字段执行验证检查。

我已经有一个编辑页面,但这会在开始时绑定所有字段 - 我正在遵循的教程清楚地表明我不应该这样做。

我的原始代码如下。由于我在开始时绑定了所有字段,因此可以使用 vans 执行检查。fieldname 如下所示,使用 'if (vans.AssetID == 20)'

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit([Bind(Include = "AssetID,Batch_Number,Customer_Account_Holder,Dealer_ID, ")] Vans__ vans)
    {
        if (vans.AssetID == 20) //Example - check if data entered for AssetID is 20
        {
          //do something
        }
        if (ModelState.IsValid)
        {
            db.Entry(vans__).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(vans__);
    }

在我遵循的教程中,我被指示不要在开始时绑定所有内容,而是使用如下代码:

    public ActionResult EditPost(int? id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }

        //In here vans is the original values and not from the form.
        Vans__ vans = db.Vans__.Find(id);

       //Here how can I check if AssetID is a certain number returned from the form?

        if (TryUpdateModel(vans, "", new string[] { "AssetID" }))
        {
            try
            {
                db.SaveChanges();
                return RedirectToAction("Index");
            }
        }
    }

我知道 TryUpdateModel 的白名单会更容易、更安全,我只是在努力掌握如何访问从表单返回到控制器的数据。

如何访问模型以添加自己的验证检查?

感谢所有帮助,谢谢。

【问题讨论】:

  • 寻找更好的教程。
  • @StephenMuecke 对于我们希望编辑的特定字段,我们是否可以更好地绑定到较小的视图模型,然后在 UpdateDB 上将视图模型绑定到数据库实体模型?这也是我们看到的一种做法。例如,当只更新 2 个字段时,绑定方法从一个类发送所有 30 个字段似乎很疯狂。
  • 是的,你不应该在编辑时在视图中使用数据模型。
  • @StephenMuecke 感谢斯蒂芬,我非常乐意接受您的建议。我们将坚持使用 Bind,但仅对我们希望编辑/更新的特定项目使用 ViewModel。
  • @AndyDonegan,使用视图模型时不需要BindAttribute

标签: c# asp.net-mvc updatemodel


【解决方案1】:

这不是答案。

The Microsoft tutorial is here(免责声明我与 James 合作并要求他通过发布问题来学习)。

并在下面写下为什么我们不应该使用 James 链接的原始 BIND 方法。

[HttpPost, ActionName("Edit")]
[ValidateAntiForgeryToken]
public ActionResult EditPost(int? id)
{
  if (id == null)
  {
    return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
  }
  var studentToUpdate = db.Students.Find(id);
  if (TryUpdateModel(studentToUpdate, "",
   new string[] { "LastName", "FirstMidName", "EnrollmentDate" }))
  {
    try
    {
        db.SaveChanges();

        return RedirectToAction("Index");
    }
    catch (DataException /* dex */)
    {
        //Log the error (uncomment dex variable name and add a line here to write a log.
        ModelState.AddModelError("", "Unable to save changes. Try again, and      if the problem persists, see your system administrator.");
    }
  }
  return View(studentToUpdate);
}

这些更改实现了防止过度发布的安全最佳实践,脚手架生成了一个 Bind 属性,并将模型绑定器创建的实体添加到带有 Modified 标志的实体集中。不再推荐使用该代码,因为 Bind 属性会清除未在 Include 参数中列出的字段中的任何预先存在的数据。将来,MVC 控制器脚手架将被更新,以便它不会为 Edit 方法生成 Bind 属性。

新代码读取现有实体并调用 TryUpdateModel 以更新已发布表单数据中用户输入的字段。实体框架的自动更改跟踪会在实体上设置已修改标志。当调用 SaveChanges 方法时,Modified 标志会导致实体框架创建 SQL 语句来更新数据库行。并发冲突被忽略,数据库行的所有列都被更新,包括那些用户没有改变的。 (后面的教程展示了如何处理并发冲突,如果您只想更新数据库中的单个字段,您可以将实体设置为 Unchanged 并将单个字段设置为 Modified。)

作为防止过度发布的最佳做法,您希望编辑页面可更新的字段在 TryUpdateModel 参数中列入白名单。目前没有您要保护的额外字段,但列出您希望模型绑定器绑定的字段可确保如果您将来向数据模型添加字段,它们会自动受到保护,直到您在此处明确添加它们。

由于这些更改,HttpPost Edit 方法的方法签名与 HttpGet edit 方法相同;因此,您已将方法重命名为 EditPost。

【讨论】:

  • 如果你认为这不是一个答案,请把它作为评论。
  • @Alpha_Wing 很难帮助解决原始问题和过去的评论。
猜你喜欢
  • 2011-08-07
  • 2018-06-01
  • 2015-11-18
  • 1970-01-01
  • 1970-01-01
  • 2014-07-27
  • 1970-01-01
  • 2012-07-05
  • 1970-01-01
相关资源
最近更新 更多