MVC3, Razor view, EditorFor, query string value overrides model value

Do I have a controller action that accepts a DateTime? via the query string as part of post-redirect-get. The controller looks like

public class HomeController : Controller { [HttpGet] public ActionResult Index(DateTime? date) { IndexModel model = new IndexModel(); if (date.HasValue) { model.Date = (DateTime)date; } else { model.Date = DateTime.Now; } return View(model); } [HttpPost] public ActionResult Index(IndexModel model) { if (ModelState.IsValid) { return RedirectToAction("Index", new { date = model.Date.ToString("yyyy-MM-dd hh:mm:ss") }); } else { return View(model); } } } 

My model:

 public class IndexModel { [DataType(DataType.Date)] [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd MMM yyyy}")] public DateTime Date { get; set; } } 

And the Razor view:

 @model Mvc3Playground.Models.Home.IndexModel @using (Html.BeginForm()) { @Html.EditorFor(m => m.Date); <input type="submit" /> } 

My problem is double:

(1) Date formatting applied to a model using the [DisplayFormat] attribute does not work if the query string contains a date value.

(2) The value stored in the model seems to be overwritten by what contains the value of the query string. For instance. if I set a breakpoint inside my GET index action method and manually set the date to today's words, if the query string contains, for example? date = 1/1/1, then "1/1/1" is displayed in the text box (the plan should confirm the date by default, if the query string is invalid).

Any ideas?

+4
source share
1 answer

Html helpers first use ModelState when binding, so if you ever intend to change some value that is present in the model state inside the controller action, be sure to remove it from ModelState first:

 [HttpGet] public ActionResult Index(DateTime? date) { IndexModel model = new IndexModel(); if (date.HasValue) { // Remove the date variable present in the modelstate which has a wrong format // and which will be used by the html helpers such as TextBoxFor ModelState.Remove("date"); model.Date = (DateTime)date; } else { model.Date = DateTime.Now; } return View(model); } 

I have to agree that this behavior is not very intuitive, but it is by design, so people really need to get used to it.

Here's what happens:

  • When you request / Home / Index, there is nothing inside the ModelState, so the Html.EditorFor(x => x.Date) uses the value of your view model (which you set in DateTime.Now ) and, of course, it uses the correct formatting
  • When you request /Home/Index?date=1/1/1 Html.EditorFor(x => x.Date) detects that there is a date variable inside ModelState equal to ModelState , and it uses that value. completely ignoring the value stored inside your view model (which is almost the same in terms of the DateTime value, but of course formatting is not applied).
+14
source

All Articles