如果匹配字段在 URL 或 post 数据中,MVC 4.5 会忽略模型中的值吗?

MVC 4.5 ignores value in model if a matching field is in URL or post data?

这个周末我看到了一些意想不到的行为。我创建了一个超级简单的页面来向正在学习它的人演示 MVC。它只有两个方法 'Index()' 和 '[HttpPost] Index(string text)'

模型包含一项,'string Text {get;set;}'

在 Index() -get 中,我创建了一个模型,并将 Text 的值设置为 "Enter some text" 并返回了 View(model)

在 cshtml 文件中,我有两个项目:

@Html.TextBoxFor (m=>m.Text)

@Model.Text

这只会显示文本的值。

还有一个提交按钮。 (提交回 Index)

这就是奇怪的地方。在 Post 方法中,我只是创建了一个新模型,将 'Text' 属性 设置为传入的任何文本 + "!!"

我预计如果我将文本设置为 'a',然后点击按钮,它应该会在文本框中重新显示 'a!!' 并在其下方显示 'a!!'。

但是,相反,编辑框的值保持不变,@Model.Text的值发生变化!

如果您使用 text=A 执行 GET URL 也会发生这种情况 - 那么无论您在模型中传递什么,它都会覆盖 TextBoxFor/TextAreaFor 中使用的值并显示 'A'!但是,来自@Model.Text 的值将正确显示为传递给视图的模型中的值。

看来他们不得不竭尽全力打破这一点 - 支持从 URL/Post 数据而不是模型获取数据。

Wtf?

控制器:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using TestApp.Models;

namespace TestApp.Controllers
{
    public class homeController : Controller
    {

       public ActionResult Index()
       {
          TestModel model = new TestModel { Text = "Enter your text here! };
          return View(model);
       }
       [HttpPost]
       public ActionResult Index(TestModel model)
       {
          model.Text = model.Text + "!!";
          return View(model);
       }

    }
}

查看:

@using TestApp.Models
@model TestModel

@using (Html.BeginForm("Index", "Home"))
{
@Html.TextAreaFor(m => m.Text, 10,50,null)
<br />
<hr />
<br />

    @Model.Text
<br>
<button type="submit">Save</button>
}

为了完整起见,模型:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace TestApp.Models
{
   public class TestModel
   {
      public string Text { get; set; }

   }
}

这是设计使然。 Request and/or ViewData(包括 ViewBag)中的值用于创建 ModelState 对象,ModelState 中的值覆盖模型。这是必要的,以便发布的值覆盖实际模型数据。

以用户发布表单但出现错误导致数据无法保存的情况为例。用户被送回表单。现在这里应该发生什么?因为数据没有保存,所以模型仍然具有来自数据库或其他任何东西的原始值。如果模型的值优先,那么用户之前输入的任何内容都将被覆盖。但是,如果使用 ModelState 值,用户会看到他们最初提交的表单,并且可以进行任何必要的修改以再次提交。显然后一种选择是最理想的选择。