我们遇到的问题是MVC3 中的Html.HiddenFor偶尔无法正确绑定。我们根本无法重现它,但我们在日志记录中看到了nullrefs,这让我们绝对疯狂。
我们有以下模型和控制器结构:
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; }
}
...以及以下视图结构:
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)
考虑到我们在初始控制器操作中检查的值小于零,因此@Html.HiddenFor(model => model.NumericID)
永远不应该具有小于零的值。
话虽这么说,当我们在AnObject
操作中使用TakePageSubmission
时,我们会得到空引用错误。
当我们挖掘model.NumericID
值时,我们看到它是零,应该不可能考虑到DummyView只能使用非零价值。
我们有点难过,因为我们无法可靠地重现这个问题,我们没有想法可能导致它的原因。有没有人遇到过这样的事情?
编辑:我们正在对表单帖子进行ModelState验证,但是我们没有检查是否通过的NumericID是0.当我们检查时,模型是无效的,这证明了HiddenFor设置不当。此外,到页面的路径实际上包括 NumericID,因此,例如,我们已经看到这种情况发生在:
http://our.site.com/RouteToReturnAPage/1736/
...操作的参数设置清楚,模型构造正确,但由于某些未知原因,HiddenFor NumericID值为0.这真是令人费解。
答案 0 :(得分:3)
您的默认0值绑定是从发布后的MVC View'ing到同一页面,认为由于帖子中的错误而重新加载相同的视图。在对不同Action调用的加载/操作调用中将发生正确的绑定。
在重新加载视图之前,ModelState.Clear();
有一个黑客解决方法。
此外,根本不使用助手创建隐藏字段,如:
<input type="hidden" value="@Model.NumericID" id="NumericID" name="NumericID" />
答案 1 :(得分:0)
首先,您缺少模型中的默认构造函数。如果没有它,应用程序会在绑定时抛出异常。
您可以通过编辑客户端的隐藏字段来重现错误。因此用户可以将id更改为0或任何其他值。如果您没有在分布式环境中运行应用程序,则使用TempData在操作之间传递id。通过这种方式,您可以确保id不被数据篡改。
TempData["NumericID"] = NumericID;