Always check the ModelState
Ever came across weird behavior in your ASP.NET Views? - I did already several times, and this is what I've learned:
Always check the
ModelState
.
Most of you probably remember to clear the ModelState
when you modify _POST_ed values. But I had to find out, that HttpPost
isn't the only way to get a messed up ModelState
.
I had a simple Action:
[HttpGet]
public ActionResult Edit(string username)
{
return View(ComponentFactory
.GetAdapter<IUserListAdapter>()
.Get(username));
}
and in the view, I just wanted to show a form for editing those details:
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
<fieldset>
<legend>Globale Benutzer</legend>
<div class="editor-label">
@Html.LabelFor(model => model.UserId)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.UserId)
@Html.ValidationMessageFor(
model => model.UserId)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.UserName)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.UserName)
@Html.ValidationMessageFor(
model => model.UserName)
</div>
<div>
<input type="submit"
value="@LocalizationHelper
.LocalizedLiteral("Save").ToString()"
/>
</div>
</fieldset>
}
While the value for Model.UserName
was the correct name of the user, the text-box (created by @Html.EditorFor(model => model.UserName)
) contained the user's id. The same value as Model.UserId
. Everything else (label, validation rules, ...) was correct and I couldn't figure out WHY.
What else could modify it?
After no answer from Stack Overflow and some more googling I came across the term ModelState
. Since I had no other clue, I thought to give it a try:
[HttpGet]
public ActionResult Edit(string username)
{
ModelState.Clear();
return View(ComponentFactory
.GetAdapter<IUserListAdapter>()
.Get(username));
}
And .... It Worked!
How does ModelState
work?
I didn't give too much attention to ModelState
before, just cleared it if it solved my problems and that's all. Yet, I didn't understand, why I would need ModelState.Clear()
in a an action as simple as this one.
So I had a deeper look, and it is actually very interesting what happens in the background.
OK, what ASP.NET does is:
- Taking all parameters you passed to the action (via
GET
orPOST
- that doesn't matter) - Storing them in a dictionary, the
ModelState
(which you can empty withModelState.Clear()
).
Later, when the view is created and @Html.EditorFor
is called, ASP.NET checks if it has a parameter with that name. (Name checks are case-in-sensitive.) If the parameter is found in the ModelState
, it is retrieved from there, instead of evaluating the Model.
So why did I have problems with it?
Now the solution is simple: My Action had the parameter named username
. Even I stored the UserId
inside. Later when @Html.EditorFor(model => model.UserName)
was called, username
from the ModelState
was retrieved. However this username
contained the UserId
, passed to the action.
Possible solutions:
- Call
ModelState.Clear()
(really bad solution, don't like it) - Rename
username
touserid
, than theModelState
will only replace oneuserId
, for the same from a different source.