Reputation: 2359
We're having an issue with Html.HiddenFor in MVC3 occasionally not getting bound properly. We can't reproduce it at all, but we're seeing nullrefs come through in our logging and it's driving us absolutely nuts.
We have the following model and controller structure:
public class DummyController
{
[HttpGet]
public ActionResult ReturnAPage(int NumericID)
{
//NumericID should never be 0 or negative, but let's check to make sure
if (NumericID < 1)
{
return RedirectToAction("TracyJordanStabbingRobot");
}
return View("DummyView", new DummyViewModel(NumericID));
}
[HttpPost]
public ActionResult TakePageSubmission(DummyViewModel model)
{
//AnObject relies on having a non-zero ID
ComplexObject AnObject = new ComplexObject(model.NumericID);
AnObject.UseMe();
}
}
public class DummyViewModel
{
public DummyViewModel() {}
public DummyViewModel(int ID)
{
NumericID = ID;
}
public int NumericID { get; set; }
}
... and the following view structure:
DummyView.cshtml
@model DummyViewModel
<html>
<head></head>
<body>
<p>THIS IS A VIEW!</p>
<form id="DummyViewForm" action="/RouteTo/TakePageSubmission" method="post">
@Html.Partial("_PartialDummyView", Model)
<input type="submit" value="Submit This!" />
</form>
</body>
</html>
_PartialDummyView.cshtml
@model DummyViewModel
<p>Heard you like views...</p>
@Html.HiddenFor(model => model.NumericID)
Considering we're checking for less-than-zero values in the initial controller action, it stands to reason that @Html.HiddenFor(model => model.NumericID)
should never have a less-than-zero value.
That being said, when we get to using AnObject
in the TakePageSubmission
action, we're getting null reference errors.
When we dug into logging the model.NumericID
value, we're seeing it come through as zero, which shouldn't be possible considering the DummyView can only be accessed with a non-zero value.
We're a little stumped and since we can't reliably reproduce the issue, we have no idea what could possibly be causing it. Has anyone run into something like this before?
Edit: We are doing ModelState validation on the form post, but we're not checking to see if the NumericID coming through is 0. When we did check for that, the model came through as invalid, which just proves that the HiddenFor is getting set improperly. Furthermore, the route to the page actually includes the NumericID, so for example, we've seen this happen on:
http://our.site.com/RouteToReturnAPage/1736/
...where the parameter for the action is clearly set, the model is constructed correctly, but for some unknown reason the HiddenFor NumericID value is 0. It's really baffling.
Upvotes: 3
Views: 1507
Reputation: 82
Your default 0 value bindings are from MVC View'ing to the same page after post, thinking it is reloading the same view due to an error during the post. The correct binding will occur on a load/action call to a different Action call.
There is a hack workaround, to ModelState.Clear();
before you reload the View.
Also, not using the Helpers to create the hidden fields at all, something like:
<input type="hidden" value="@Model.NumericID" id="NumericID" name="NumericID" />
Upvotes: 3
Reputation: 1208
First you are missing default constructor in your model. Without it applicaiton throws exception when binding.
You can reproduce the error by editing the hidden field on client side. So user can change id to 0 or any other value. If you aren't running you application on distributed enviroment then use TempData to pass the id between actions. This way you will keep id safe from data tampering.
TempData["NumericID"] = NumericID;
Upvotes: 0