Частичные представления 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 объяснение:
- Посмотрите на div, который содержит мое частичное (class="partal") и найдите форму в этом div
- Удалите любые другие события "submit" с помощью этой формы (я получал странную ошибку двойного представления, пока я не сделал эту привязку).
- используйте "живой", чтобы после замены контента он снова связывался
- Как только мы входим в функцию partalViewUpdate...
- Не позволяйте форме завершить отправку, чтобы она могла быть обработана ajax.
- получить div, который содержит мой частичный (будет использовать это позже)
- Настройте URL поста jquery, взяв его из формы, $(this).attr("action")
- Возьмите форму (то есть нашу модель) и сериализуйте ее для функции контроллера $(this).serialize()
- Создайте функцию, которая будет обрабатывать возвращаемое значение ajax.
- Я использую свой личный объект 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);
Таким образом, информация об ошибке будет сохранена, и представление будет корректным.