我有一个模型类(我们称之为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'。
发生了什么事?我错过了什么?
答案 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发回到控制器它来自,我最终必须以上述方式将发布的数据重定向到所需的控制器,以便将所有逻辑保持在一个地方。也许不是最好的设计,嗯?