Значение MVC 3 потеряно после отправки клиенту - PullRequest
0 голосов
/ 04 августа 2011

Я, должно быть, что-то упускаю из-за того, как это работает, потому что я не могу понять это.Может быть, кто-то здесь может помочь.

У моего объекта Address есть свойство ValidationStatus.Он не виден на экране, но имеет скрытое поле:

@Html.HiddenFor(model => model.ValidationStatus)

Итак, я запускаю программу, открываю существующий адрес с ValidationStatus «OK» и изменяю адрес так, чтобыэто недействительно.Затем я отправляю форму в контроллер.Метод Validate объекта вызывает стороннюю службу, которая возвращает ошибку.Код устанавливает ValidationStatus на «Invalid» и возвращает View с сообщением проверки.

Когда загружается View, ValidationStatus правильно устанавливается на «Invalid», как я вижу, отлаживая следующий оператор в View:1008 *

@if (Model.ValidationStatus == "Invalid") //show an additional field.

Итак, я ввожу данные в новое поле и снова отправляю форму в контроллер.В первой строке контроллера я ставлю точку останова и проверяю коллекцию ["ValidationStatus"] в ближайшем окне.Это «OK» вместо «Invalid».

Что мне здесь не хватает?Почему ценность не придерживается?На стороне клиента нет ничего, что могло бы изменить это значение.

Вот код контроллера (на самом деле довольно простой):

[HttpPost]
public ActionResult Index(FormCollection collection, string destinationControllerName)
{
    PrepareSecondaryData(); // loads drop-down lists in case the View needs to be returned

    try
    {
        if (!TryUpdateModel(_policy))
            return View(_policy);

        if (!_services.PolicyEditor.SavePolicy(_policy))
            return View(_policy);
    }
    catch (Exception exp)
    {
        UIHelper.Log(UIHelper.LogLevel.Error, this, "Error during Save", exp);
        ViewBag.Error = UIHelper.GenericErrorMessage();
        return View(_policy);
    }

    return RedirectToAction("Index", destinationControllerName);
}

Ответы [ 2 ]

2 голосов
/ 04 августа 2011

При рендеринге представления клиенту, ModelState имеет самый высокий приоритет в предоставлении значений модели.Это имеет место в вашей ситуации.Когда представление впервые отправляется клиенту, ValidationStatus, соответствующее ModelState["ValidationStatus"], не имеет значения, поэтому принимает значение модели - «ОК».Когда сообщение публикуется на сервере, ModelState["ValidationStatus"] заполняется «ОК» - отправляется из скрытого поля от клиента.При проверке третьей стороной и возврате обратно, даже если model.ValidationStatus == "Invalid", ModelState["ValidationStatus"] == "OK", поэтому в соответствии с более высоким приоритетом последней, ModelState устанавливает значение «ОК» для модели.И клиент получает значение «ОК» в скрытом поле.Чтобы исправить это, сделайте что-то вроде

  ModelState["ValidationStatus"].Value = new ValueProviderResult("Invalid", "Invalid", CultureInfo.CurrentCulture);

Общая идея состоит в том, что соответствующая запись в массиве ModelState должна иметь правильное значение для модели.

ОБНОВЛЕНИЕ:

Или, в качестве альтернативы, очистите значение от состояния модели, чтобы MVC использовал значение из модели.ModelState.Remove("ValidationStatus")

1 голос
/ 05 августа 2011

В коде, который вы разместили, больше, чем вы думаете:)

Прежде всего, ваш код не одинаков все время, когда вы отображаете представление. В первый раз, вы будете исходить из этого метода, я полагаю:

[HttpGet]
public ActionResult Index()

Обратите внимание на HttpGet. Вы не включили код этого метода, но я думаю, что вы получите данные для отображения, передадите их в ViewData.Model, а затем отобразите представление.

После первого поста этот метод полностью исключен. В случае ошибки вы визуализируете представление непосредственно из вашего HttpPost метода, и это очень серьезный недостаток дизайна. Это напрямую не влияет на вашу проблему, но ее решение даст вам как рабочий код, так и лучший дизайн в целом.

В качестве предпосылки, я рекомендую вам зайти в Google по адресу PRG PATTERN , а затем продолжить читать здесь.

Некоторое время спустя ...

Теперь, когда вы являетесь экспертом и настоящим поклонником PRG PATTERN (я уверен, что вам это нравится), я дам вам несколько советов о том, как его реализовать, и о распространенных проблемах, которые вы могли бы столкнуться.

Прежде всего, ваш HttpGet метод не изменится. Это почему? Здесь уже есть ответ от @archil, но я все равно объясню. Значения, содержащиеся в ModelState, имеют приоритет над ViewData.Model. Это сделано для сохранения ввода пользователя при повторном отображении формы.

Я знаю, что будет следующим, что придет вам в голову. При использовании шаблона PRG ModelState теряется при перенаправлении. Это правда. Вот почему ребята из MvcContrib сделали этот маленький волшебный ActionFilter, который заставляет все работать. Атрибут ModelStateToTempData при применении к методу POST или даже ко всему контроллеру заставит сериализовать любой ModelState в методе POST в TempData и десериализовать обратно в первый метод GET, вызванный после этого.

Таким образом, у вас будет: POST -> Обработка данных / ошибка -> Сериализация ModelState -> Перенаправление на метод GET для отображения формы -> Десериализация TempData обратно в ModelState -> Прибыль.

Курсив - это то, что автоматически выполняется атрибутом ModelStateToTempData.

Я уверен, что после того, как вы выполните рефакторинг своего кода в соответствии с паттерном PRG, ваша ошибка исчезнет, ​​и вы добавите в свой набор очень полезный навык и предотвратите те неприятные сообщения «повторной отправки формы», которые вы встретимся в плохо продуманных формах.

Надеюсь, это поможет вам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...