我一定不知道这是如何运作的,因为我无法理解这一点。也许这里有人可以提供帮助。
我的地址对象有一个名为ValidationStatus的属性。它在屏幕上不可见,但有一个隐藏的字段:
@Html.HiddenFor(model => model.ValidationStatus)
因此,我运行程序,打开一个现有地址,其ValidationStatus为“OK”,并更改地址以使其无效。然后我将表单发布到Controller。对象的Validate方法调用第三方服务,该服务返回错误。该代码将ValidationStatus设置为“Invalid”并返回带有验证消息的View。
当View加载时,ValidationStatus被正确设置为“Invalid”,我可以通过在视图中调试以下语句看到:
@if (Model.ValidationStatus == "Invalid") //show an additional field.
所以我在新字段中输入数据并再次将表单发布到Controller。在控制器的第一行,我在一个立即窗口中放置一个断点并检查集合[“ValidationStatus”]。它是“OK”而不是“Invalid”。
我在这里缺少什么?为什么价值不坚持?客户端没有任何东西可以改变这个价值。
这是控制器代码(非常基本,真的):
[HttpPost]
public ActionResult Index(FormCollection collection, string destinationControllerName)
{
PrepareSecondaryData(); // loads drop-down lists in case the View needs to be returned
try
{
if (!TryUpdateModel(_policy))
return View(_policy);
if (!_services.PolicyEditor.SavePolicy(_policy))
return View(_policy);
}
catch (Exception exp)
{
UIHelper.Log(UIHelper.LogLevel.Error, this, "Error during Save", exp);
ViewBag.Error = UIHelper.GenericErrorMessage();
return View(_policy);
}
return RedirectToAction("Index", destinationControllerName);
}
答案 0 :(得分:2)
在向客户端呈现视图时,ModelState在提供模型值方面具有最高优先级。在你的情况下就是这种情况。当视图第一次发送到客户端时,ValidationStatus
对应的ModelState["ValidationStatus"]
没有值,因此它需要模型的值 - “OK”。当它发布到服务器时,ModelState["ValidationStatus"]
填充“OK” - 从客户端的隐藏字段发送。并且当由第三方验证并再次返回时,即使model.ValidationStatus == "Invalid"
,ModelState["ValidationStatus"] == "OK"
,因此根据后者的更高优先级,ModelState为模型设置值“OK”。并且客户端在隐藏字段中获得值“OK”。要修复它,请执行类似
ModelState["ValidationStatus"].Value = new ValueProviderResult("Invalid", "Invalid", CultureInfo.CurrentCulture);
一般的想法是ModelState数组中的相应记录应该具有正确的模型值。
更新:
或者,从modelstate清除值,使MVC使用模型中的值。 ModelState.Remove("ValidationStatus")
答案 1 :(得分:1)
您发布的代码中的内容超出您的想法:)
首先,您的代码在渲染视图时始终不一样。第一次,你会从这种方法出发,我推测:
[HttpGet]
public ActionResult Index()
请注意HttpGet
。您没有包含此方法的代码,但我认为您将获取要显示的数据,将其传递给ViewData.Model,然后呈现视图。
在第一篇文章之后,完全省略了这种方法。如果出现错误,您将直接从HttpPost
方法渲染视图,这是一个非常严重的设计缺陷。它不会直接影响您的问题,但解决这个问题将为您提供工作代码和更好的整体设计。
作为前提,我建议您谷歌 PRG PATTERN ,然后继续阅读。
一段时间后......
既然你是 PRG PATTERN 的专家和真正的粉丝(我相信你喜欢它)我会给你一些关于如何实现它以及常见问题的提示可能会遇到。
首先,您的HttpGet
方法不会发生变化。这是为什么? @archil已经有了答案,但无论如何我都会解释。 ModelState中包含的值优先于ViewData.Model。这样做是为了在重新显示表单时保留用户输入。
我知道你脑子里会想到的下一件事是什么。使用PRG模式时,ModelState在执行重定向时会丢失。确实如此。这就是为什么MvcContrib的人们做了这个神奇的ActionFilter,让一切运转起来。 ModelStateToTempData
属性,当应用于POST方法,甚至应用于整个控制器时,将使POST方法中的任何ModelState在TempData中序列化,并在之后调用的第一个GET方法中反序列化。
所以你将拥有:POST - >处理数据/错误 - > ModelState的序列化 - >重定向到GET方法以显示表单 - > 将TempData反序列化回ModelState - >利润。
斜体是由ModelStateToTempData
属性自动执行的内容。
我确信,在你重构你的代码后,按照PRG PATTERN,你的错误将会消失,你将为你的设置添加一个非常有用的技能,并防止你那些讨厌的“重新提交”消息碰巧遇到设计糟糕的形式。
希望这会对你有所帮助。