MVC 4:我的表单是发布模型列表 - 所以 - 模型错误在哪里?

时间:2013-12-20 18:28:23

标签: asp.net-mvc-4 model-binding

我有一个模型类(我们称之为OrderLineModel),它实现了IValidatableObject。

当我在表单上呈现一个行列表时,我遍历父模型的“lines”属性(让我们称之为Order)并吐出一些非想象力的剃刀代码:

 @For Each item In Model.Lines
    Dim currentItem = item
        @<tr>
        <td>
            @Html.TextBox("[" & i & "].Quantities.Tentative", currentItem.Quantities.Tentative) 
            @Html.Hidden("[" & i & "].Quantities.Actual", currentItem.Quantities.Actual)
            @Html.Hidden("[" & i & "].SKU", currentItem.SKU)
            @Html.Hidden("[" & i & "].OrderID", currentItem.OrderID)

        </td>

        <td>
            @Html.DisplayFor(Function(modelItem) currentItem.Quantities.Actual)
        </td>
        </tr>
    i = i + 1
    Next

HTML表单成功地将所需对象(即模型绑定似乎正常工作)发布到我的控制器上的以下操作签名

<HttpPost()>
Function SaveLines(ByVal Id As Long, postedOrderLines As List(Of OrderLineModel)) As ActionResult

现在,我可以将断点放入默认模型绑定器调用的Validate()方法中,并且可以看到正在添加的模型错误以及返回的ValidationResult对象列表。

但是,在上述控制器操作中,ModelState.IsValid始终返回true。就好像它被清除了一样。我可以发布完整的控制器动作,但是,它真的不是很奇特..我可以在它执行任何逻辑之前将断点放在动作的第一行上(换句话说,直接在模型绑定完成之后和Validate方法)已被调用)并将鼠标悬停在ModelState.IsValid上,当我知道模型状态中应该有错误时,显示'true'。

发生了什么事?我错过了什么?

1 个答案:

答案 0 :(得分:0)

确定。这是我的用户错误..但是很好!

因此,经过进一步调查后,FORM会发回一个完全不同的控制器类和动作。那个人然后将控制传递给我原始帖子中的控制器动作。所以,这就是我的ModelState迷失的原因。

这是发布到的'实际'控制器操作(并且它的ModelState在应该的时候正确无效) - 我只是小心翼翼地传递了controllerContext - 结果证明是不够的。

<HttpPost()>
Function EditLines(ByVal Id As Long, postedLines As List(Of OrderLineModel)) As ActionResult
        Dim lineControl As New LinesController()
        lineControl.ControllerContext = Me.ControllerContext
        Return lineControl.SaveLines(Id, postedLines)
End Function

似乎没有办法(我知道)将调用的控制器的只读'modelstate'属性传递给不同的控制器实例。所以这是我必须采取的修复措施。

<HttpPost()>
Function EditLines(ByVal Id As Long, postedLines As List(Of OrderLineModel)) As ActionResult

    If Me.ModelState.IsValid Then
        Dim lineControl As New LinesController()
        lineControl.ControllerContext = Me.ControllerContext
        Return lineControl.SaveLines(Id, postedLines)
    Else
        Return EditLine(Id, postedLines(0).SKU)
    End If
End Function

为什么我有两个不同的控制器操作来处理相同的表单POST? 很难解释除了说我有两个不同的用户体验路径(或两个不同的业务场景)需要不同的控制器,但每个使用相同的视图剃刀..并且因为剃刀FORM发回到控制器它来自,我最终必须以上述方式将发布的数据重定向到所需的控制器,以便将所有逻辑保持在一个地方。也许不是最好的设计,嗯?