当我使用默认模型绑定将表单参数绑定到作为操作参数的复杂对象时,框架会记住传递给第一个请求的值,这意味着对该操作的任何后续请求都会获得与第一个请求相同的数据.参数值和验证状态在不相关的Web请求之间保持不变.
这是我的控制器代码(service
表示访问应用程序的后端):
[AcceptVerbs(HttpVerbs.Get)] public ActionResult Create() { return View(RunTime.Default); } [AcceptVerbs(HttpVerbs.Post)] public ActionResult Create(RunTime newRunTime) { if (ModelState.IsValid) { service.CreateNewRun(newRunTime); TempData["Message"] = "New run created"; return RedirectToAction("index"); } return View(newRunTime); }
我的.aspx视图(强类型为ViewPage
<%= Html.TextBox("newRunTime.Time", ViewData.Model.Time) %>
这使用了DefaultModelBinder
类,它用于自动绑定我的模型的属性.
我点击页面,输入有效数据(例如时间= 1).应用程序正确保存新对象时间= 1.然后我再次点击它,输入不同的有效数据(例如时间= 2).但是,保存的数据是原始数据(例如,时间= 1).这也会影响验证,因此如果我的原始数据无效,那么我将来输入的所有数据都将被视为无效.重新启动IIS或重建我的代码会刷新持久状态.
我可以通过编写自己的硬编码模型绑定器来解决问题,其中一个基本的简单示例如下所示.
[AcceptVerbs(HttpVerbs.Post)] public ActionResult Create([ModelBinder(typeof (RunTimeBinder))] RunTime newRunTime) { if (ModelState.IsValid) { service.CreateNewRun(newRunTime); TempData["Message"] = "New run created"; return RedirectToAction("index"); } return View(newRunTime); } internal class RunTimeBinder : DefaultModelBinder { public override ModelBinderResult BindModel(ModelBindingContext bindingContext) { // Without this line, failed validation state persists between requests bindingContext.ModelState.Clear(); double time = 0; try { time = Convert.ToDouble(bindingContext.HttpContext.Request[bindingContext.ModelName + ".Time"]); } catch (FormatException) { bindingContext.ModelState.AddModelError(bindingContext.ModelName + ".Time", bindingContext.HttpContext.Request[bindingContext.ModelName + ".Time"] + "is not a valid number"); } var model = new RunTime(time); return new ModelBinderResult(model); } }
我错过了什么吗?我不认为这是一个浏览器会话问题,因为如果第一个数据在一个浏览器中输入而第二个数据在另一个浏览器中输入,我可以重现该问题.
事实证明,问题是我的控制器在呼叫之间被重用.我选择从原始帖子中省略的一个细节是我使用Castle.Windsor容器来创建我的控制器.我没有用Transient生活方式标记我的控制器,所以我在每次请求时都得到了相同的实例.因此,粘合剂使用的上下文正在被重用,当然它包含陈旧的数据.
我在仔细分析Eilon的代码和我的代码之间的区别时发现了这个问题,消除了所有其他可能性.正如Castle文档所说,这是一个"可怕的错误"!让这成为别人的警告!
感谢您的回复Eilon - 抱歉占用您的时间.