ASP.Net MVC ModelState / Html.TextBox 回传问题

5
我在尝试进行表单提交时遇到了问题。在表单未通过验证的情况下,我按照标准流程调用了ModelState.AddModelError(),然后返回一个视图结果。
问题在于,HTML.*助手应该在呈现时捕获已发布的值,但我注意到,只有当我将它们包含在回发操作的参数列表中时,我的文本字段才会这样做,这不应该是必需的,因为有些表单具有太多字段,不想将它们全部列出作为参数。
我的操作代码大致如下:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult EditDataDefinition(long? id, string name)
{
    var dataDefinition = ...

    // do some validation stuff
    if (!ModelState.IsValid)
    {
        // manually set checkbox fields via ViewData seeing as this STILL doesn't work in MC 1.0 :P
        // ...
        return View(dataDefinition);
    }

}

现在,数据定义(即 LINQ to SQL 实体)有一个字段MinVolume,在视图中由以下行处理:

Minimum: <%= Html.TextBox("MinVolume", null, new { size = 5 })%>

然而,当我们的视图在ModelState验证失败后被呈现时,原始页面中输入的值未被保留,除非我将其作为postback方法的参数包含在内。简而言之,我可以通过以下方式“解决问题”:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult EditDataDefinition(long? id, string name, string minVolume)

由于某种原因,需要保留字段值。我觉得这很愚蠢,因为我的表单不仅有这个字段,还有其他更多的值,我不应该只为这个字段添加一个参数。

有什么想法吗?

6个回答

6

哇,我刚刚改进了我的应用程序设计。

问题出现在你有自定义验证(我也有)。

你需要在之后添加以下内容:

ModelState.AddModelError()

this

ModelState.SetModelValue("MinVolume", ValueProvider["MinVolume"]);

就我的看法,它必须是这样的

Mimum:<%=Html.Textbox("MinVolume")%>

我还不确定为什么它有效,但对我来说确实有效。


哦...这可能是答案!明天上班时会检查一下。谢谢。 - Nathan Ridley
2
它能够工作是因为它将值添加到模型中,从而助手可以提取这些值。使用UpdateModel也可以实现相同的效果,这也是我使用它的原因,因为我的文本框值得以保留。 - tvanfosson

4

你的代码是否存在以下问题:

<%= Html.TextBox("MinVolume", null, new { size = 5 })%>

..在默认值参数中使用了null?也许如果你将null更改为Model.MinVolume,它就会保留这个值。像这样:

<%= Html.TextBox("MinVolume", Model.MinVolume, new { size = 5 })%>

我不确定你的操作是否在模型中返回值MinVolume。如果是,上述代码应该可以工作。否则,您可能需要稍微重构一下这个操作。


不,指定 null 应该指定使用现有的模型上下文来查询值。指定 MinVolume 是显式的,并将强制使用该值而不是先前提交的值。 - Nathan Ridley
不正确。指定MinVolume会查找ViewDataDoctionary,然后是ModelStateDictionary用于后续的提交。因此,如果Model.MinVolume在编辑之前为5,则指定MinVolume将把5放入TextBox中。然后,如果进行了提交(例如值为3),但发现无效,则第二次显示TextBox将显示3。您试过吗?通常在“新建”或“创建”视图上指定null,以便初始提交在字段中显示为空,并且后续提交保留输入的值。 - Matt Kocaj
这正是我做事的方式,每次都有效。我从未见过需要指定 null 的地方。如果你能提供一个链接,那就太好了。 - sirrocco

3
当您在错误时设置ModelState中的值时,您使用的密钥是什么?设置TextBox的值参数的代码如下所示: 下载框架代码的相关部分。
string attemptedValue = (string)htmlHelper.GetModelStateValue(name, typeof(string));
tagBuilder.MergeAttribute("value", attemptedValue ?? ((useViewData) ? htmlHelper.EvalString(name) : valueParameter), isExplicitValue);

如您所见,如果尝试值存在,则会使用它——但仅当相同的键可用时。

我知道这个方法可行,因为我有一个不带参数的操作,直接从ValueProvider获取值,并使用AddModelError指示验证错误。 我确信我的TextBoxes中的值已被保留。

编辑:为了保留值,它们需要以某种方式与模型相关联。 一种方法是将它们添加到参数列表中。 另一种方法是使用UpdateModel(在白名单或无白名单中使用参数名称)。 第三种方法是像@Jenea的答案中那样明确将参数添加到模型中。 由于助手只从模型状态中提取,因此它们必须在其中才能保留值。 它不查看请求的Form属性。


该字段根本没有经过验证-在这个阶段它不需要被验证。因此,它只是表单中的“无辜旁观者”,期望如果其他字段不正确地行为并导致表单再次呈现,则保留其新值。 - Nathan Ridley
我突然想知道是否错误地假设ModelState应该尝试保留与Model匹配的所有字段的名称。也许它只保留通过参数列表传递或通过AddModelError引用的字段?如果是这样,那么看起来有点愚蠢,因为当然我想保留表单中的所有内容,而不仅仅是特定情况。再说,MVC仍然无法正确地保留复选框字段... - Nathan Ridley

0

据我理解,解决方案是:

[Transaction]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult EditDataDefinition(int id, FormCollection form)
{
    T itemToUpdate = repository.Get(id);
    UpdateModel(itemToUpdate, form.ToValueProvider());

    if (itemToUpdate.IsValid())
    {
        repository.SaveOrUpdate(itemToUpdate);
        return Json(ValidationResultToJson(itemToUpdate.ValidationResults()));
    }

    repository.DbContext.RollbackTransaction();
    return Json(ValidationResultToJson(itemToUpdate.ValidationResults()));
}

祝你好运!


0
请参考本文,了解在ASP.NET MVC中处理postback的不同方法。

链接文本


不错的文章,适合初学者。 - Altaf

0

另一个解决方案是如果您键入视图:

<%var minVolume=Request["MinVolume"]??"";%>
<%=Html.Textbox("MinVolume",minVolume,new {size=5})%>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接