Html.HiddenFor и Html.Hidden не корректно возвращаются к контроллеру

У меня возникла проблема с помощью помощников HiddenFor и Hidden для хранения данных, которые будут отправлены обратно в контроллер. У меня есть контроллер с двумя способами:

Function Index() As ActionResult
 Dim model As New FormPOSTViewModel With {.Name = "Test", .Description = "Test description goes here", .Value = 12}
 Return View(model)
End Function

<httppost>
Function Update(model As FormPOSTViewModel) As ActionResult
 Dim updated As New FormPOSTViewModel
 updated.Name = model.Name & "_x"
 updated.Description = model.Description & "_x"
 updated.Value = model.Value * 2
 Return View("Index", updated)
End Function
</httppost>

и вид с тремя формами, один с использованием HTML, один с использованием HiddenFor и один с помощью Hidden:

@ModelType MVCAjaxWorkbench.FormPOSTViewModel

@Using Html.BeginForm("Update", "FormPOST")
 @:
 @:
 @:
 @:
 @:
 @:<table><tbody><tr><td>@Html.DisplayFor(Function(m) Model.Name)</td></tr></tbody></table>
 @:
End Using

@Using Html.BeginForm("Update", "FormPOST")
 @:
 @:
 @:
 @:
 @:
 @:<table><tbody><tr><td>@Html.DisplayFor(Function(m) Model.Name)</td></tr><tr><td>@Html.Hidden("Name", Model.Name)</td></tr><tr><td>@Html.Hidden("Description", Model.Description)</td></tr><tr><td>@Html.Hidden("Value", Model.Value)</td></tr></tbody></table>
 @:
End Using

@Using Html.BeginForm("Update", "FormPOST")
 @:
 @:
 @:
 @:
 @:
 @:<table><tbody><tr><td>@Html.DisplayFor(Function(m) Model.Name)</td></tr><tr><td>@Html.HiddenFor(Function(m) Model.Name)</td></tr><tr><td>@Html.HiddenFor(Function(m) Model.Description)</td></tr><tr><td>@Html.HiddenFor(Function(m) Model.Value)</td></tr></tbody></table>
 @:
End Using

и ViewModel:

Public Class FormPOSTViewModel
 Public Property Name As String
 Public Property Description As String
 Public Property Value As Integer
End Class

Я хочу, чтобы модель обновлялась каждый раз, когда нажата кнопка "Отправить", добавляя "_x" до конца несколько раз, чтобы она заканчивалась чем-то вроде "Test_x_x_x_x_x_x". Если я использую кнопку "Отправить" в форме, где я создал HTML вручную, все работает нормально.

Однако то, что на самом деле происходит, когда я запускаю это и нажимаю одну из других кнопок Submit, заключается в том, что когда-либо добавляется только один "_x". Кажется, это связано с тем, что модель, которую метод Update получает во второй и последующие времена, представляет собой модель, отправленную на страницу по методу исходного индекса.

Эта ошибка с Hidden/HiddenFor или я использую их неправильно?

2 ответа

Из блога Simon Ince, в котором содержится описание проблемы и почему использование запроса ModelState.Clear требуется:

ASP.NET MVC предполагает, что если вы создаете представление в ответ на HTTP POST, а вы используете Html Helpers, то вы, скорее всего, будете перерисовывать форму, которая не прошла проверку. Таким образом, помощники Html действительно проверяют ModelState на значение, отображаемое в поле, прежде чем они будут выглядеть в модели. Это позволяет им повторно отображать ошибочные данные, введенные пользователем, и соответствующее сообщение об ошибке, если это необходимо.

Поскольку наша [HttpPost] перегрузка индекса основывается на привязке модели для анализа данных POST, ModelState автоматически заполняется значениями полей. В нашем действии мы изменяем данные модели (а не ModelState), но Html Helpers (то есть Html.Hidden и Html.TextBox) сначала проверяют ModelState... и поэтому отображают значения, которые были получены действием, а не те, которые мы изменили.

Таким образом, чтобы решить проблему, мы должны добавить строку к методу обновления контроллера:

Function Update(model As FormPOSTViewModel) As ActionResult
 Dim updated As New FormPOSTViewModel
 updated.Name = model.Name & "_x"
 updated.Description = model.Description & "_x"
 updated.Value = model.Value * 2
 <span>ModelState.Clear()</span>
 Return View("Index", updated)
End Function


Нет, это не ошибка. Когда вы отправляете назад модель, значение свойств добавляется в ModelState. Когда вы возвращаете представление, это значение в ModelState имеет приоритет над любым значением, которое вы можете попытаться переопределить в контроллере. Сначала нужно очистить значения ModelState используя

ModelState.Clear();

Теперь, когда вы устанавливаете значение свойства, помощники Html будут использовать значение свойства.

licensed under cc by-sa 3.0 with attribution.