Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is my MVC ViewModel member overridden by my ActionResult parameter?

Is this a bug or a feature?

All code below has been simplified for the sake of brevity and easy replication and does not actually do anything useful other than highlight the behavior.

I have a class that includes an int named ID:

public class FooterLink
{
    public int ID { get; set; }
}

In my controller, I have an Edit actionresult that takes a parameter called 'id':

public ActionResult Edit(int id)
{
    return View(new FooterLink() { ID = 5 }); //notice that I am explicitly setting the ID value here.
}

in my index view I have a link to the edit action that specifies the 'id' parameter:

<%= Html.ActionLink("Edit", "Edit", new { id = 1 })%>

In my view I have a couple of text boxes:

<%= Html.TextBox("ID", Model.ID)%>
<%= Html.TextBox("Blah", Model.ID) %>

which renders the following in HTML:

<input id="ID" name="ID" type="text" value="1">
<input id="Blah" name="Blah" type="text" value="5">

Notice that the input with an id of "ID" is getting its value not from the Model like I am telling it to...but from the parameter that was supplied to my ActionResult. This behavior is the same with Html.TextBoxFor, Html.Hidden, Html.HiddenFor, etc.

What gives?

EDIT: I meant to update this a long time ago but never got around to it. The reason that this is happening is because the ModelState will have an "id" entry with the value of the "id" parameter in the method and the MVC ViewEngine first checks the ModelState when filling in Html helpers instead of the Model. In order to work around this, you can simply add the following line in your controller just before the return:

ModelState.Remove("id");

Now the <%= Html.TextBox("ID", Model.ID)%> will get the value from the Model and not the ModelState. Problem solved.

like image 277
Bradley Mountford Avatar asked Aug 12 '10 22:08

Bradley Mountford


1 Answers

That's how html helpers work. They will first look if there's ID parameter in the request url and use that value instead of the one specified as second argument in the model.

like image 94
Darin Dimitrov Avatar answered Sep 18 '22 14:09

Darin Dimitrov