MVC 4.5 ignores value in model if a matching field is in URL or post data?
I saw some unexpected behavior this weekend. I created a super simple page to demonstrate MVC to someone who was learning it. It simply had two methods 'Index()' and '[HttpPost] Index(string text)'
model contained one item, 'string Text {get;set;}'
in Index() -the get, I created a model, and set the value of Text to "Enter some text" and returned View(model)
In the cshtml file, I had two items:
@Html.TextBoxFor (m=>m.Text)
and
@Model.Text
Which would just display the value of Text.
And a submit button. (Submitted it back to Index)
Here is where it gets weird. In the Post method, I simply created a new model, set the 'Text' property to whatever text was passed in + "!!"
I expected that if I set the text to 'a', and hit the button, it should redisplay 'a!!' in the text box as well as display 'a!!' below that.
However, instead, the value of the edit box remains the same, and the value of the @Model.Text changes!
This will also happen if you execute GET URL with text=A - then no matter what you pass in your model, it will OVERRIDE the value used in the TextBoxFor/TextAreaFor and show 'A'! But, the value from @Model.Text will be correctly displayed as the value in the model passed to the view.
It seems they had to go out of their way to break this - supporting getting data from the URL/Post Data instead of the model.
Wtf?
Controller:
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);
}
}
}
View:
@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>
}
And for completeness, the model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace TestApp.Models
{
public class TestModel
{
public string Text { get; set; }
}
}
This is by design. Values from Request
and/or ViewData
(which includes ViewBag
) are used to create the ModelState
object, and values in ModelState
override values in the model. This is necessary in order for posted values to override the actual model data.
Take for example the situation where a user posts a form, but has an error that prevents the data from being saved. The user is sent back to the form. Now what should happen here? Because the data was not saved, the model still has the original values from the database or whatever. If the model's values took precedence, then anything the user had previously entered would be overwritten. However, if the ModelState
values are used, the user sees the form as they originally submitted it and can make any necessary modifications to submit again. Obviously the latter option is the ideal one.
上一篇: 我如何删除或替换SVG内容?