How to display ValidationSummary using multiple forms using MVC

I reviewed many of the proposed solutions on this site and others for my problem, but none of them work perfectly for my solution.

On my Layout page, I have an input area at the top of the screen. This is always present if the user is not logged in. This login form has a ValidationSummary on it, and every time I send a message back using another form on the site, a check is run for this login form.

I am pretty sure that this is due to the way I call this login page from my layout page. This is not a partial view, which is in the shared folder, it is in the area in my project. On my Layout page, I invoke the login form as follows:

@Html.Action("LogOn", "Account", new { area = "Store" }) 

The login page contains the following:

 @model Project.ViewModels.LogOn_ViewModel @{ Layout = null; } @using (Ajax.BeginForm("LogOn", "Account", new { @area = "Store" }, new AjaxOptions { HttpMethod = "Post", UpdateTargetId = "LoginContainer", LoadingElementId = "actionLoaderImage" }, new { id="LogonForm" })) { @Html.AntiForgeryToken() <div class="loginArea"> <div class="notRegistered"> <h4>Not registered yet?</h4> Register now<br/> @Html.ActionLink("Register", "Index", "SignUp", new { area = "Store" }, new { @class = "greenButton" }) </div> <!-- /notRegistered --> <div class="loginForm"> <div class="formFields"> <label class="inline">@Html.LabelFor(m => m.UserName)</label> @Html.TextBoxFor(m => m.UserName) <label class="inline">@Html.LabelFor(m => m.Password)</label> @Html.PasswordFor(m => m.Password) <input type="submit" name="LogIn" value="Log in" class="blueButton" /> <img id="actionLoaderImage" src="@Url.Content("~/Content/web/images/loader.gif")" alt="icon" style="margin-right:15px; display:none;" /> @Html.ValidationSummary() </div> </div> <!-- /loginForm --> </div> <!-- /loginArea --> } 

The login controller is standard material:

  // GET: /Account/Logon public ActionResult LogOn() { // if logged in show logged in view if (User.Identity.IsAuthenticated) return View("LoggedIn"); return View(); } // POST: /Account/Logon [HttpPost] public ActionResult LogOn(LogOn_ViewModel model) { if (ModelState.IsValid) { if (SecurityService.Login(model.UserName, model.Password, model.RememberMe)) { return View("LoggedIn"); } else { ModelState.AddModelError("", "The user name or password provided is incorrect."); } } return PartialView(model); } 

I suspect that what is happening here is that Html.Action is the β€œsubmitting” of the login form if the message appears elsewhere on the page. This makes sense since the layout page itself will be hosted as part of the post form’s action.

I tried to implement custom Validator examples from some other SO questions and blogs ( http://blogs.imeta.co.uk/MBest/archive/2010/01/19/833.aspx ), but I found that using these examples is not will display a validation summary with client-side validation, which is not very convenient for me.

The solution I'm looking for would have to allow both client-side and server-side validation to appear for the correct form. Does anyone have an example of something like this using MVC? I would like to avoid manually escaping client-side validation with jquery if possible, and just use the framework to handle this work for me.

Thanks for your suggestions, Rich.

+4
source share
1 answer

After playing with this problem longer than I would like to admit, the answer, as always, was simple, as soon as you know how to do it!

The solution to this problem for everyone who encounters it is to rename your action so that your POST action is a different name for your GET action. That way, when the layout page goes back and starts the PartialView, which will also be sent back, there is only a GET action for your PartialView, so the ValidationSummary will not start.

Based on my example above, I changed the postback form to another action for my partial login view, and this solved this problem for me.

On my Layout page, the partial link in the store area remains the same:

 @Html.Action("LogOn", "Account", new { area = "Store" }) 

The action of the login form is then modified to indicate a new action - not called by the same name as the GET action:

  @using (Ajax.BeginForm("ConfirmLogon", "Account", new { @area = "Store" }, new AjaxOptions { HttpMethod = "Post", UpdateTargetId = "LoginContainer", LoadingElementId = "actionLoaderImage" }, new { id="LogonForm" })) { .... } 

Then I just renamed the action of my controller, so that it has a different action name for the POST action, so when the layout page is called using the message, and the partial one is loaded with the POST action, which it does not trigger the POST login action:

  // POST: /Account/ConfirmLogon [HttpPost] public ActionResult ConfirmLogon(LogOn_ViewModel model) { if (ModelState.IsValid) { if (SecurityService.Login(model.UserName, model.Password, model.RememberMe)) { return PartialView("LoggedIn"); } else { ModelState.AddModelError("", "The user name or password provided is incorrect."); } } return PartialView("Logon",model); } 

Hope this helps some others in this matter. It seems so obvious now, but drove me nuts: D

+2
source

All Articles