3

我偶然发现了 ASP.Net MVC 的一个非常奇怪的情况,传递一个“id”作为操作参数和一个“id”隐藏表单元素。我有一个带有“id”参数的动作。这个 id 值代表一个项目。我有一个控制器操作,我正在创建一个数据输入表单,用于将员工分配给传入的项目(我创建一个下拉列表,管理员在其中选择要分配给通过的项目的员工)。通过将员工分配给项目,我创建了一个 ProjectEmployee 记录(项目 id、员工 id 和一个表示组合的 id,它是数据库中的一个身份列)。身份列(名为“id”)也是一个隐藏的表单元素。这是必要的,因为我需要能够在以后编辑项目/员工分配。

无论如何,在为项目创建新员工分配时,项目 id(即传递给操作的“id”)将应用于“id”隐藏表单元素。

我将 117 传递给行动。117 是项目 ID。它被设置为应为 0 的“id”隐藏字段,因为 0 表示新项目/员工分配。

查看模型

id  - unique id that represents the Project/Employee combination
projectId - the "Id" being passed to action
EmployeeId - what the admin is selecting from drop down
rate
startdate
endDate
...

数据输入表

@Html.HiddenFor(m => m.Id) 
@Html.HiddenFor(m => m.ProjectId)
...
Id: @Model.Id <br />
ProjectId: @Model.ProjectId<br />

因此,@Html.HiddenFor(m => m.Id) 呈现一个隐藏的表单元素,其值为 117。@Model.Id 向 UI 呈现 0。单步执行代码,我可以直观地看到 Id 属性的值是 0。HiddenFor 是如何让它的电线交叉并拉出 117 的值?

这个错误已经进入生产,所以我手上的数据变得一团糟,因为我没有在数据库表中创建新记录,而是在更新现有记录,因为“Id”属性被错误地设置了从 0(表示新记录)到 117(即 projectId),因此正在更新不同的记录。

4

2 回答 2

7

HiddenFor 怎么会越过它并拉动 117 的值?

这是设计使然。TextBoxFor 和 HiddenFor 等所有 HTML 助手在绑定时首先使用 ModelState 的值,然后再使用模型的值。我认为您的控制器操作如下所示:

public ActionResult Foo(int id)
{
    SomeModel model = ...
    // At this stage model.Id = 0
    return View(model);
}

问题是默认模型绑定id器使用助手使用的键将值添加到 ModelState 中,并且模型属性值被忽略。这不是错误。这就是 HTML 助手的设计方式。当你不知道的时候,一开始有点困惑,但是一旦你习惯了这种行为,你就不会第二次陷入陷阱。

解决此问题的一种可能性是从 ModelState 中删除此值:

public ActionResult Foo(int id)
{
    ModelState.Remove("id");
    SomeModel model = ...
    // At this stage model.Id = 0
    return View(model);
}

或者将Id模型中的属性重命名为其他名称以避免冲突。

于 2012-06-25T14:18:29.373 回答
1

作为更改字段名称的替代方法,您可以创建一个新的辅助方法,在评估放入 value 属性的内容时不使用路由值。

我为极其常见的情况创建了这个助手id

public static MvcHtmlString HiddenIdFor<TModel, TValue>(this HtmlHelper<TModel> html,
        Expression<Func<TModel, TValue>> expression)
    {
        var value = ModelMetadata.FromLambdaExpression(expression, html.ViewData).Model.ToString();
        var builder = new TagBuilder("input");
        builder.MergeAttribute("type", "hidden");
        builder.MergeAttribute("name", ExpressionHelper.GetExpressionText(expression));
        builder.MergeAttribute("value", value);
        return MvcHtmlString.Create(builder.ToString(TagRenderMode.SelfClosing));

}

然后你可以在模板中使用它:

@Html.HiddenIdFor(m => m.Id) 
@Html.HiddenIdFor(m => m.ProjectId)
于 2017-04-14T05:50:17.303 回答