发送给客户端后MVC 3价值丢失

时间:2011-08-04 13:32:05

标签: asp.net-mvc asp.net-mvc-3

我一定不知道这是如何运作的,因为我无法理解这一点。也许这里有人可以提供帮助。

我的地址对象有一个名为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);
}

2 个答案:

答案 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,你的错误将会消失,你将为你的设置添加一个非常有用的技能,并防止你那些讨厌的“重新提交”消息碰巧遇到设计糟糕的形式。

希望这会对你有所帮助。