Частичные представления ASP.Net MVC сохраняют свое модельное состояние? - PullRequest
9 голосов
/ 21 июня 2010

Это, вероятно, снова вопрос новичка.

Когда я создаю приложение ASP.NET MVC2, контроллер учетной записи с логином действия создается следующим образом:

[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
   if (ModelState.IsValid)
   {
      if (MembershipService.ValidateUser(model.UserName, model.Password))
      {
         FormsService.SignIn(model.UserName, model.RememberMe);
         if (!String.IsNullOrEmpty(returnUrl))
         {
            return Redirect(returnUrl);
         }
         else
         {
           return RedirectToAction("Index", "Home");
         }
       }
       else
       {
          ModelState.AddModelError("", "The user name or password provided is incorrect.");
       }
     }

        // If we got this far, something failed, redisplay form
        return View(model);
    }

Теперь я не хочу иметь страницу входа в систему, я хочу иметь элементы управления входом в систему как часть более крупной страницы. Итак, я изменил Login.aspx на Login.ascx и интегрирую его в свой основной вид либо с Html.RenderPartial, либо с Html.RenderAction.

И то и другое работает как шарм, если вход в систему прошел успешно. Если это не так,

return View(model)

убивает меня. Я хочу вернуться на мою главную страницу (назовите ее Home / Index), но с информацией об ошибке частичного просмотра.

return RedirectToAction("Index", "Home")

Очевидно, не работает.

Подсказка

Ответы [ 5 ]

3 голосов
/ 11 февраля 2011

Это, конечно, не вопрос новичка, и я причесался в Интернете, чтобы найти ответ на эту проблему, и до сих пор лучшее решение, которое я нашел, было спрятано в этом уроке здесь .Это то, что Дарин Димитров предлагал с обновлением Ajax.Я кратко опишу важные части этой ссылки и почему это не так легко исправить: /

Обновление Ajax на основе странного любовника

Решение с обновлением Ajaxв значительной степени зависит от следующей функции (странный любовник использует ControllerContext, но он для меня не существовал, поэтому у меня есть ControllerExtension):

ControllerExtension.RenderPartialViewToString(this,"mypartial", (object)model)

Эта функция - то, что берет вашу модель + состояние модели и возвращает ваш частичный вид вHTML-строка.Затем вы можете взять эту строку и отправить ее обратно в json-объект в некоторый javascript для обновления представления.Я использовал jquery, и это выглядит так:

$(document).ready(function () {
    var partialViewUpdate = function (e) {
            e.preventDefault(); //no postback
            var partialDiv = $(this).parent(".partial");
            $.post($(this).attr("action"),
                   $(this).serialize(),
                   function (json) {
                   if (json.StatusCode != 0) {
                       // invalid model, return partial 
                       partialDiv.replaceWith(json.Content);
                   }
                   else if (json.Content != null && json.Content != "") {
                       window.location.replace(data.Content);
                   };
           });

    $(".partial").find("form")
                 .unbind('submit')
                 .live("submit", partialViewUpdate);
};

Объяснение Jquery:

  1. Найдите div, который содержит мою частичную (class = "partal "), и найдите форму вэтот div
  2. Отсоедините любые другие события "submit" с этой формой (у меня возникла странная ошибка двойного представления, пока я не сделал это unbind).
  3. используйте "live", чтобы после замены содержимогоон снова связывается
  4. Как только мы входим в функциюpartalViewUpdate ...
  5. Запретить завершению отправки формы, чтобы она могла быть обработана ajax.
  6. получить divкоторый содержит мою часть (буду использовать это позже)
  7. Установите URL-адрес поста jquery, взяв его из формы, $ (this) .attr ("action")
  8. Примите форму (т.е.наша модель) и сериализовать его для функции контроллера, $ (this) .serialize ()
  9. Создать функцию, которая будет обрабатывать возвращаемое значение ajax.
  10. Я использую свой собственный объект json,где StatusCode 1 плохо.Так что, если это плохо, тогда я беру то, что в Content, это строка, которую RenderPartialViewToString дал мне, и я просто заменяю содержимое div, которое содержит мой частичный.

Почему он не «просто работает» нормально

Так что причина, по которой партиалы не работают только с проверкой состояния модели, заключается в том, что вы не можете вернуть View (модель) с POST, потому чтоMVC разрешит это в адрес маршрута частичного представления (login.ascx) вместо того, где встроено частичное (index.aspx).

Вы также не можете использовать RedirectAction (), потому что это отправит егоto (index.aspx) функция контроллера, которая эквивалентна очистке всего и обновлению страницы index.aspx.Однако, если вы используете ActionFilter, предложенный Chino и Thabaza, тогда, когда ваша страница обновляется и функция контроллера login.ascx снова запускается, она получает эти временные данные.Это, однако, не работает, если обновление страницы вызывает хлопоты с кодом на стороне клиента, таким как всплывающие модалы (т.е. если вы обновляете, ваше всплывающее окно исчезло).

Скажите это не так

Я бы предпочел, чтобы это «просто сработало», поэтому, если кто-нибудь знает правильный / лучший способ сделать это, поделитесь им!Я до сих пор чувствую, что решения Ajax refresh и ActionFilter не являются чистым способом сделать это, потому что они почти создают впечатление, что частичные представления с формами невозможно использовать без какого-либо «трюка».

1 голос
/ 21 июня 2010

Да, redirecttoaction, но с сообщением об ошибке в tempdata, поэтому вы должны сделать что-то вроде этого

TempData["errorMsg"] = "incorrect values provided";
return RedirectToAction("Index", "Home")

Конечно, в главном индексе у вас должен быть div, который отображает сообщение

<%= html.Encode(TempData["errorMsg"]) %>

EDIT Я вижу, вы хотите сохранить состояние модели, что может быть проблемой, но вы могли бы передать состояние модели в действии index или передать объект модели в tempdata. Затем вы можете проверить, есть ли в объекте ошибки состояния модели, и если они есть, проверить поле и добавить ошибку в правильное поле.

0 голосов
/ 06 июля 2011

У меня была такая же проблема при использовании Ajax.BeginForm, где мне нужно было вернуть частичное представление, но все ошибки состояния модели исчезли.Какова хитрость в том, чтобы изолировать часть Ajax.BeginForm в отдельном представлении, и RenderPartial это представление внутри div UpdateTargetId в другом, содержащем представление.

Таким образом вы можете вернуть модель представления с ошибками модели, когдаимейте их, или просто покажите некоторое успешное сообщение по вашему выбору (если есть).Вот отличное, подробное объяснение: http://xhalent.wordpress.com/2011/02/05/using-unobtrusive-ajax-forms-in-asp-net-mvc3/

0 голосов
/ 22 июня 2010

Взгляните на практику № 13 в этом блоге . Этот метод хорошо работает для передачи информации о состоянии модели при кодировании в стиле PRG (Post-Redirect-Get). Вам просто нужно создать пару фильтров действий и применить их к действиям получения и публикации в зависимости от ситуации.

0 голосов
/ 21 июня 2010

Вы можете явно указать возвращаемое представление:

return View("~/Views/Home/Index.aspx", model);

Таким образом, информация об ошибке будет сохранена, и представление будет корректно отображено.

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