6

Here is my scenario.

  1. Created two Models that have a common property name

    public class SimpleModel1
    {
    // Some Properties
    
    public string Property1 { get; set; }
    
    }
    
    public class SimpleModel2
    {
    // Some Properties
    
    public string Property1 { get; set; } // Same name as Property1 in SimpleModel1
    
    }
    
  2. Used SimpleModel1 in an Action (for e.g. Index) that returns a view that looks like this

    @model MvcApplication2.Models.SimpleModel1
    
    @{
    ViewBag.Title = "Home Page";
    }
    
    @using (Html.BeginForm("Test", "Home", FormMethod.Post))
    {
      <label>Enter something here</label>
       @Html.TextBoxFor(m => m.Property1)
       <button type="submit">Submit</button>
    }
    
  3. Submitted the value to a Test action that takes SimpleModel1 as parameter, does some work, and returns a view that takes in SimpleModel2

    public ActionResult Test(SimpleModel1 model)
    {
        SimpleModel2 newModel = new SimpleModel2();
    
        // Do Something
    
        newModel.Property1 = "Something different than model's Property1";
    
        return View(newModel);
    }
    
  4. The Test.cshtml (view returned by Test action) is as below:

    @model MvcApplication2.Models.SimpleModel2
    
    @{
        ViewBag.Title = "Test";
    }
    
    <h2>Test</h2>
    
     @* Model Propery without using HTML extension*@
     @Model.Property1
    
     @* Model property using HTML extension (Incorrect) *@
    
     @Html.TextBoxFor(m => m.Property1)
     @Html.HiddenFor(m => m.Property1)
     @Html.TextAreaFor(m => m.Property1)
    
      @* Correct Value *@
     <input value="@Model.Property1" />
    

What I expect is that all the values of Property1 would be "Something different than model's Property1" as set in Test Action. But it turns out that the ones that use the Html extension (Html.TextBoxFor, Html.HiddenFor etc) have the Property1 value that was posted to Test Action. For example, if I post "What a surprise" ( the Property1 of SimpleModel1) to Test Action, the value of Property1 of SimpleModel2 is also "What a surprise" no matter what I set it to.

I have no idea what is going on. Looks like a bug to me. Does anyone have any idea?

Pitamber Tiwari
  • 536
  • 1
  • 6
  • 19

1 Answers1

12

You will see this behavior when doing a POST because posted data is persisted in ModelState. The value for Property1 will be whatever the value was posted for this property. In order to see your new value you need to include this line of code in your ActionResult Test:

ModelState.Clear();

As a general rule just remember to include this line in case you are posting data, modifying it and trying to see modified data on the returned view.

Dmitry Efimenko
  • 10,973
  • 7
  • 62
  • 79
  • This worked but why is this a problem with html extension methods? How come the @Model.Property1 show the correct value? – Pitamber Tiwari Dec 19 '12 at 18:26
  • Internally html extension methods look at the value in ModelState to determine the value for the property. This is just how they are written. I cannot tell why they are written like this. Hopefully someone else can. I'd be interested to know as well. – Dmitry Efimenko Dec 19 '12 at 18:39
  • 4
    @Dmitry If you had a post method that instead of taking a ViewModel, took in several parameters individually, or you used the form collection to retrieve values, then on a POST with a failed validation, you don't have to piece meal construct a new viewmodel and set all the various properties from the form elements because the form will be populated automatically from the ModelState. For the rest of us using a ViewModel in the POST parameter, it becomes an annoyance for ModelState to take precedence over the view Model. – AaronLS Dec 19 '12 at 21:02
  • Not defending their design, but from what I've read that is its intended purpose. – AaronLS Dec 19 '12 at 21:02