ASP.NET MVC - Как поддерживать ModelState с другого контроллера?
У меня есть HomeController с действием индекса, которое показывает представление Index.aspx. Он имеет логин/пароль для входа в раздел. Когда пользователь нажимает кнопку отправки, он отправляется в действие "Вход" в AccountController.
<% Html.BeginForm("Login", "Account", FormMethod.Post); %>
В этом действии он проверяет правильность имени пользователя и пароля и, если он недействителен, отправляет пользователя обратно на страницу входа с сообщением о том, что учетные данные были плохими.
[HttpPost]
public ActionResult Login(LoginViewModel Model, string ReturnUrl)
{
User user = MembershipService.ValidateUser(Model.UserName, Model.Password);
if (user != null)
{
//Detail removed here
FormsService.SignIn(user.ToString(), Model.RememberMe);
return Redirect(ReturnUrl);
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
// If we got this far, something failed, redisplay form
return RedirectToAction("Index", "Home"); // <-- Here is the problem. ModelState is lost.
}
Но здесь проблема: ValidationSummary всегда пуста, потому что мы теряем модель, когда мы RedirectToAction.
Итак, вопрос: Как отправить пользователя на действие на другом контроллере без перенаправления?
Ответы
Ответ 1
Как утверждают другие, принято возвращать представление, если проверка не выполняется, но по мере того, как вы вызываете из своего контроллера учетных записей, вы хотите указать полный путь к вашему представлению
return View("~/Views/Home/Index.aspx", model);
или
Также часто возникает отдельная страница входа и перенаправление на эту страницу, если сбой входа в систему. Обе страницы будут отправляться в одно и то же действие входа. Facebook делает это, например.
или
Поскольку вы хотите отобразить сообщение об ошибке
return RedirectToAction("Index", "Home", new { LoginAttempts = 1 });
то в действии индекса введите параметр LoginAttempts
и выберите соответствующее сообщение об ошибке.
Ответ 2
Используйте TempData
для сохранения состояния между запросами. Используйте специальные атрибуты для удобства, как показано здесь.
Несколько моментов, чтобы упомянуть:
- Не возвращать View прямо из вашего POST-действия, уважать шаблон Post-Redirect-Get.
- Не злоупотребляйте
TempData
. Он только должен сохранять состояние модели прямо перед перенаправлением и извлекать его сразу после перенаправления.
Ответ 3
Три варианта
-
Вы можете вызвать действие напрямую, но клиентская сторона не изменит URL. Поэтому вместо вызова RedirectToAction
вы можете напрямую вызвать метод Index()
класса HomeController
.
HomeController c = new HomeController();
c.ViewData = this.ViewData;
return c.Index(data);
Это немного сложно. Возможно, вам придется установить и другие вещи, кроме ViewData
, которые необходимы для ModelState
.
-
Вы также можете использовать словарь TempData
и заполнить его любыми данными, которые вы хотите, и использовать их.
-
Самый простой, когда вы предоставляете полный путь к представлению
return View("~/Views/Home/Index.aspx", data);
Лучшее предложение, используемое крупными игроками
Если мы посмотрим, как другие сайты используют этот сценарий. Возьмем, например, Twitter (Поскольку @David говорит Facebook, очевидно, делает то же самое). Вы можете войти в систему из действия Home/Index
(так сказать, если оно было разработано с использованием Asp.net MVC). Но при неудаче входа в систему отображается отдельная страница входа, в которой отображаются ошибки проверки. В вашем случае это будет Account/SignIn
. Это будет иметь смысл, и вы можете напрямую вернуть свое представление с ошибками проверки. Когда все будет в порядке, вы сделаете это, как вы это делаете сейчас. Вернитесь обратно к Home/Index
.
Ответ 4
Ну, вы всегда можете это сделать
return View("~/Views/Home/Index.aspx", myModel);
Это не реальное перенаправление, URL-адрес клиента все равно укажет на /login/, но по крайней мере у вас есть ваше модальное состояние
Ответ 5
Попробуйте использовать
return View("Index", "Home", Model)