Common mistake or misunderstanding why login action doesn’t have ReturnUrl value, even if there is string parameter with value in the page URL. If you think about it more, you will get it – ReturnUrl is in the page URL but not in the action URL of the login form. The trick is to pass this parameter to the form inputs or action URL parameters be submitted with login form request. It’s very easy to do with MVC.
First, in the view pass parameter to the form by specifying rote parameter for form action:
@model LogOnModel @{ ViewBag.Title = "Login | kitsula.com"; Layout = "~/Views/Shared/_Layout.cshtml"; } <h1>LogOn</h1> <img src="/Content/Img/login.png" alt="Login" id="imgLogin" /> @using (Html.BeginForm("LogOn", "Account", new { ReturnUrl = Request.QueryString["ReturnUrl"]}, FormMethod.Post, new { @id = "formLogOn"})) { @Html.ValidationSummary(true, "Login was unsuccessful. Please correct the errors and try again.") <div> <fieldset> <legend></legend> <div class="editor-label"> @Html.LabelFor(m => m.UserName) </div> <div class="editor-field"> @Html.TextBoxFor(m => m.UserName) @Html.ValidationMessageFor(m => m.UserName) </div> <br class="clearer" /> <div class="editor-label"> @Html.LabelFor(m => m.Password) </div> <div class="editor-field"> @Html.PasswordFor(m => m.Password) @Html.ValidationMessageFor(m => m.Password) </div> <br class="clearer" /> <div class="editor-label"> </div> <div class="editor-field"> @Html.CheckBoxFor(m => m.RememberMe) @Html.LabelFor(m => m.RememberMe) </div> <br class="clearer" /> @Html.HiddenFor(m => m.ReturnUrl) <div class="editor-label"> </div> <div class="editor-field"> <input type="submit" value="Log On"/> </div> </fieldset> </div> }
ReturnUrl parameter will be passed to the server with form submit request. Now we should handle it on the server. You can declare on action handler separate ReturnUrl parameter or it can be a part of the login model:
public class LogOnModel { [Required] [StringLength(30)] [DisplayName("Username")] public string UserName { get; set; } [Required] [StringLength(50)] [DataType(DataType.Password)] [DisplayName("Password")] public string Password { get; set; } [DisplayName("Remember me?")] public bool RememberMe { get; set; } public string ReturnUrl { get; set; } }
And action itself:
// // POST: /Account/LogOn [HttpPost] public ActionResult LogOn(LogOnModel model) { if (ModelState.IsValid) { if (new KitsulaMembershipProvider().ValidateUser(model.UserName, model.Password)) { FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe); if (!string.IsNullOrEmpty(model.ReturnUrl)) return Redirect(model.ReturnUrl); return RedirectToAction("Index", "Home"); } ModelState.AddModelError("Password", "The user name or password provided is incorrect."); } // If we got this far, something failed, redisplay form return View(model); }
On successful login just check if ReturnUrl is not empty and redirect to the URL or default action.
Comments
Thank you very much!! This was exactly what I needed! You rock! : )
if we need to another window like failure message so hoew to achieve it.
Join the discussion