The name may not be so clear (because I could not find a better one), but what I'm trying to understand is when you have a normal (as opposed to partial) view, usually there is a GET action method that simply displays the view with a new instance view models and the POST action method (usually with the same name) that takes an instance of the view model as a parameter. Inside the POST action method, you check the ModelState if it is valid, what you are doing, what you should do if you do not render the view again with the same instance of the view model to display any errors.
This is actually one of the things I really like about ASP.NET MVC, but how does it work with Partial Views? If I return a partial view with an instance of the view model, it will only display a partial view with a white background, outside the context of the entire web application. And if I send back the normal view passing the instance of the view model, it throws a StackOverflowException.
Here is an example:
public ActionResult Login() { return PartialView(new LoginViewModel()); } [HttpPost] public ActionResult Login(LoginViewModel dto) { bool flag = false; if (ModelState.IsValid) { if (_userService.AuthenticateUser(dto.Email, dto.Password, false)) { var user = _userService.GetUserByEmail(dto.Email); var uSession = new UserSession { ID = user.Id, Nickname = user.Nickname }; SessionManager.RegisterSession(SessionKeys.User, uSession); flag = true; if(dto.RememberMe) { _appCookies.Email = dto.Email; _appCookies.Password = dto.Password; } } } if (flag) return RedirectToAction("Index", "Home"); else { ViewData.Add("InvalidLogin", "The login info you provided were incorrect."); return View(dto);
UPDATE: Here is the login view:
@inherits ModelWebViewPage<Sharwe.MVC.ViewModels.LoginViewModel> <div class="userFormHeader"><h2>Login</h2></div> <div id="loginBox"> @using(Html.BeginForm("Login", "User", FormMethod.Post)) { @Html.ValidationSummary(true) <div id="loginFormFields"> <div class="display-field">@this.TextBox(m => m.Email).Class("emailField").Attr("rel", "email").Class("autoText")</div> <div class="display-field">@this.TextBox(m => m.Password).Class("passwordField").Attr("rel", "password").Class("autoText")</div> <div>@this.CheckBox(m => m.RememberMe) <span class="smallText">remember me</span></div> </div> <div id="loginFormActions"> <div><input type="submit" id="loginSubmit" class="okButton" name="loginSubmit" value="Ok" /></div> <div> @this.Html.ActionLink("forgot password", "ForgotPassword", "User", new { @class = "verySmallText" } )</div> </div> } </div>
So how do I do this? Any suggestions?
UPDATE: (after Darin's answer)
Here's what my login action method looks like:
[HttpPost] public ActionResult Login(LoginViewModel dto) { bool flag = false; if (ModelState.IsValid) { if (_userService.AuthenticateUser(dto.Email, dto.Password, false)) { var user = _userService.GetUserByEmail(dto.Email); var uSession = new UserSession { ID = user.Id, Nickname = user.Nickname }; SessionManager.RegisterSession(SessionKeys.User, uSession); flag = true; if (dto.RememberMe) { //create the authentication ticket var authTicket = new FormsAuthenticationTicket( 1, user.Id.ToString(), //user id DateTime.Now, DateTime.Now.AddMinutes(20), // expiry true, //true to remember "", //roles "/" ); //encrypt the ticket and add it to a cookie var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(authTicket)); Response.Cookies.Add(cookie); } } } if (flag) { return Json(new { redirectTo = Url.Action("Index", "Home") }); } else { ViewData.Add("InvalidLogin", "The login info you provided were incorrect."); return PartialView(dto); } }