Частичные представления ASP.Net MVC сохраняют свое модельное состояние?

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

Когда я создаю приложение ASP.NET MVC2, создается Account Controller с Action LogIn, например:

[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 ответов

Решение

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

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

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

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

Эта функция - то, что берет ваше model + modelstate и перерисовывает ваше частичное представление в 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" с помощью этой формы (я получал странную ошибку двойного представления, пока я не сделал эту привязку).
  3. используйте "живой", чтобы после замены контента он снова связывался
  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(), потому что это отправит его в функцию контроллера (index.aspx), которая эквивалентна очистке всего и обновлению страницы index.aspx. Однако, если вы используете ActionFilter, предложенный Chino и Thabaza, то когда ваша страница обновится и функция контроллера login.ascx снова будет запущена, она получит эти временные данные. Это, однако, не работает, если обновление страницы вызывает хлопоты с клиентским кодом, таким как всплывающие модалы (то есть, если вы обновляете, ваше всплывающее окно исчезло).

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

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

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

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

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

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

РЕДАКТИРОВАТЬ Я вижу, что вы хотите сохранить состояние модели, которое может быть проблемой, но вы могли бы передать состояние модели в действии index или передать объект модели в tempdata. Затем вы можете проверить, есть ли в объекте ошибки модельного состояния, и если они есть, проверьте поле и добавьте ошибку в правильное поле.

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

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

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

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

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

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

Другие вопросы по тегам