PartialViews and Validation (Postback)

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); //causes a StackOverflowException } } 

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); } } 
+4
source share
1 answer

As you said in the comments section, AJAX is an option for you, how could you continue AJAXifying for the login form. The jquery form plugin is great for this job, and I highly recommend it.

Thus, you can specify the login form identifier in the login window:

 @inherits ModelWebViewPage<Sharwe.MVC.ViewModels.LoginViewModel> <div class="userFormHeader"><h2>Login</h2></div> <div id="loginBox"> @using(Html.BeginForm("Login", "User", null, FormMethod.Post, new { id = "loginForm" })) { ... } </div> 

and then enable javascript, which will be AJAxify in this form:

 $(function() { ajaxifyLoginForm(); }); function ajaxifyLoginForm() { $('#loginForm').ajaxForm({ success: function(html) { $('#loginBox').html(html); ajaxifyLoginForm(); } }); } 

Now all that remains is to return a partial view from the action of the Login controller in case of an error:

 return PartialView(dto); 

We also need to handle the success case. This can be done by returning a JSON string:

 return Json(new { redirectTo = Url.Action("Index", "Home") }); 

and then adapt the client script:

 function ajaxifyLoginForm() { $('#loginForm').ajaxForm({ success: function(data) { if (data.redirectTo != null && data.redirectTo != '') { // Everything went fine => the user is successfully // authenticated let redirect him window.location.href = data.redirectTo; } else { // the model state was invalid or the user entered incorrect // credentials => refresh the login partial in the DOM and // reajaxify the form: $('#loginBox').html(data); ajaxifyLoginForm(); } } }); } 
+2
source

Source: https://habr.com/ru/post/1347522/


All Articles