title: Handling model state and validation in a complex view using multiple partials in ASP.NET MVC
body: <p>I'm having a little trouble in getting my head around how to break up my views and actions into manageable chunks in ASP.NET MVC, and I've tried searching but I'm still none the wiser.</p>
  
  <p>In order to try and just get my head around this particular aspect I've created a little test project where I try to understand the situation using the example of a login form and register form on the same page. My view model for this looks as below:</p>
  
  <pre><code>public class LoginOrRegisterModel
  {
      public LoginModel Login { get; set; }
      public RegisterModel Register { get; set; }
  
      public LoginOrRegisterModel()
      {
          this.Login = new LoginModel();
          this.Register = new RegisterModel();
      }
  }
  
  public class LoginModel
  {
      [Required]
      public string UserName { get; set; }
      [Required]
      public string Password { get; set; }
  }
  
  public class RegisterModel
  {
      [Required]
      public string UserName { get; set; }
      [Required]
      public string Password { get; set; }
  }
  </code></pre>
  
  <p>I then started with thinking about the main action.</p>
  
  <pre><code>    public ActionResult Index()
      {
          return View(new LoginOrRegisterModel());
      }
  </code></pre>
  
  <p>...and view... </p>
  
  <pre><code>@model MvcSandbox.Models.LoginOrRegisterModel
  @{
      ViewBag.Title = "Index";
  }
  
  &lt;h2&gt;Login Or Register&lt;/h2&gt;
  
  @Html.Partial("Login", model: Model.Login)
  @Html.Partial("Register", model: Model.Register)
  </code></pre>
  
  <p>...with partial views...</p>
  
  <pre><code>@model MvcSandbox.Models.LoginModel
  @{
      ViewBag.Title = "Login";
  }
  
  &lt;h2&gt;Login&lt;/h2&gt;
  @using (Html.BeginForm())
  {
      @Html.ValidationSummary(true)
      @Html.EditorFor(model =&gt; model)
      &lt;button&gt;Login&lt;/button&gt;
  }
  
  @model MvcSandbox.Models.RegisterModel
  @{
      ViewBag.Title = "Register";
  }
  
  &lt;h2&gt;Register&lt;/h2&gt;
  @using (Html.BeginForm())
  {
      @Html.ValidationSummary(true)
      @Html.EditorFor(model =&gt; model)
      &lt;button&gt;Register&lt;/button&gt;
  }
  </code></pre>
  
  <p>I found that I had to make sure the properties of the LoginOrRegisterModel weren't null otherwise I got the error: The model item passed into the dictionary is of type 'MvcSandbox.Models.LoginOrRegisterModel', but this dictionary requires a model item of type 'MvcSandbox.Models.LoginModel'.</p>
  
  <p>That's fine so far, although not very useful at the moment as both forms have the same field names and ids and both post back to an index page that does nothing.</p>
  
  <p>HTML source:</p>
  
  <pre><code>&lt;h2&gt;Login Or Register&lt;/h2&gt;
  
  &lt;h2&gt;Login&lt;/h2&gt;
  &lt;form action="/Membership" method="post"&gt;&lt;div class="editor-label"&gt;&lt;label for="UserName"&gt;UserName&lt;/label&gt;&lt;/div&gt;
  &lt;div class="editor-field"&gt;&lt;input class="text-box single-line" data-val="true" data-val-required="The UserName field is required." id="UserName" name="UserName" type="text" value="" /&gt; &lt;span class="field-validation-valid" data-valmsg-for="UserName" data-valmsg-replace="true"&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;div class="editor-label"&gt;&lt;label for="Password"&gt;Password&lt;/label&gt;&lt;/div&gt;
  &lt;div class="editor-field"&gt;&lt;input class="text-box single-line" data-val="true" data-val-required="The Password field is required." id="Password" name="Password" type="text" value="" /&gt; &lt;span class="field-validation-valid" data-valmsg-for="Password" data-valmsg-replace="true"&gt;&lt;/span&gt;&lt;/div&gt;
      &lt;button&gt;Login&lt;/button&gt;
  &lt;/form&gt;
  
  &lt;h2&gt;Register&lt;/h2&gt;
  &lt;form action="/Membership" method="post"&gt;&lt;div class="editor-label"&gt;&lt;label for="UserName"&gt;UserName&lt;/label&gt;&lt;/div&gt;
  &lt;div class="editor-field"&gt;&lt;input class="text-box single-line" data-val="true" data-val-required="The UserName field is required." id="UserName" name="UserName" type="text" value="" /&gt; &lt;span class="field-validation-valid" data-valmsg-for="UserName" data-valmsg-replace="true"&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;div class="editor-label"&gt;&lt;label for="Password"&gt;Password&lt;/label&gt;&lt;/div&gt;
  &lt;div class="editor-field"&gt;&lt;input class="text-box single-line" data-val="true" data-val-required="The Password field is required." id="Password" name="Password" type="text" value="" /&gt; &lt;span class="field-validation-valid" data-valmsg-for="Password" data-valmsg-replace="true"&gt;&lt;/span&gt;&lt;/div&gt;
      &lt;button&gt;Register&lt;/button&gt;
  &lt;/form&gt;
  </code></pre>
  
  <p>Anyway what I then looked to do, as I kind of wanted to keep the logic separate for each post, was make each form post to a different action. And this is where I think I'm going horribly wrong.</p>
  
  <p>Essentially if validation fails I figured I needed to do something to try and actually build back up the model state when loading the page but I kind of got to what I have below and I'm kind of lost as to what approach I should be taking instead.</p>
  
  <pre><code>public class MembershipController : Controller
  {
      //
      // GET: /Membership/
  
      public ActionResult Index()
      {
          if (TempData["ModelState"] != null)
              ModelState.Merge((ModelStateDictionary)TempData["ModelState"]);
  
          return View(new LoginOrRegisterModel());
      }
  
      [HttpPost]
      public ActionResult Login(LoginModel model)
      {
          if (ModelState.IsValid)
          {
              // do something
          }
  
          TempData["ModelState"] = ModelState;
  
          return RedirectToAction("Index");
      }
  
      [HttpPost]
      public ActionResult Register(RegisterModel model)
      {
          if (ModelState.IsValid)
          {
              // do something
          }
  
          TempData["ModelState"] = ModelState;
  
          return RedirectToAction("Index");
      }
  }
  </code></pre>
  
  <p>...with the views...</p>
  
  <pre><code>@model MvcSandbox.Models.LoginModel
  @{
      ViewBag.Title = "Login";
  }
  
  &lt;h2&gt;Login&lt;/h2&gt;
  @using (Html.BeginForm("Login", "Membership"))
  {
      @Html.ValidationSummary(true)
      @Html.EditorFor(model =&gt; model)
      &lt;button&gt;Login&lt;/button&gt;
  }
  
  @model MvcSandbox.Models.RegisterModel
  @{
      ViewBag.Title = "Register";
  }
  
  &lt;h2&gt;Register&lt;/h2&gt;
  @using (Html.BeginForm("Register", "Membership"))
  {
      @Html.ValidationSummary(true)
      @Html.EditorFor(model =&gt; model)
      &lt;button&gt;Register&lt;/button&gt;
  }
  </code></pre>
  
  <p>The problem is because each model has fields of the same name validation is shown on both forms regardless of which is submitted, and when I've tried using an HtmlFieldPrefix I seem to get no validation at all.</p>
  
  <p>Any advice on how I can break up my actions and views into manageable and maintainable chunks without giving myself this headache over model state and validation would be greatly appreciated.</p>
  
  <p><strong>UPDATE:</strong></p>
  
  <p>I've changed approach slightly to use partial actions which seems to improve things, code below:</p>
  
  <pre><code>    public ActionResult Index()
      {
          return View();
      }
  
      public ActionResult Login()
      {
          if (TempData["LoginModelState"] != null)
              ModelState.Merge((ModelStateDictionary)TempData["LoginModelState"]);
  
          return View(new LoginModel());
      }
  
      [HttpPost]
      public ActionResult Login(LoginModel model)
      {
          if (ModelState.IsValid)
          {
              // do something
          }
  
          TempData["LoginModelState"] = ModelState;
  
          return RedirectToAction("Index");
      }
  
      public ActionResult Register()
      {
          if (TempData["RegisterModelState"] != null)
              ModelState.Merge((ModelStateDictionary)TempData["RegisterModelState"]);
  
          return View(new RegisterModel());
      }
  
      [HttpPost]
      public ActionResult Register(RegisterModel model)
      {
          if (ModelState.IsValid)
          {
              // do something
          }
  
          TempData["RegisterModelState"] = ModelState;
  
          return RedirectToAction("Index");
      }
  </code></pre>
  
  <p>My index view is now:</p>
  
  <pre><code>@{
      ViewBag.Title = "Index";
  }
  
  &lt;h2&gt;Login Or Register&lt;/h2&gt;
  
  @Html.Action("Login")
  @Html.Action("Register")
  </code></pre>
  
  <p>And login and register:</p>
  
  <pre><code>@model MvcSandbox.Models.LoginModel
  
  &lt;h2&gt;Login&lt;/h2&gt;
  @using (Html.BeginForm("Login", "Membership"))
  {
      @Html.ValidationSummary(true)
      @Html.EditorFor(model =&gt; model)
      &lt;button&gt;Login&lt;/button&gt;
  }
  
  @model MvcSandbox.Models.RegisterModel
  
  &lt;h2&gt;Register&lt;/h2&gt;
  @using (Html.BeginForm("Register", "Membership"))
  {
      @Html.ValidationSummary(true)
      @Html.EditorFor(model =&gt; model)
      &lt;button&gt;Register&lt;/button&gt;
  }
  </code></pre>
  
  <p>Now to me this has the advantage over the previous approach that it actually seems to work a little more and gets rid of need for the quite frankly horribly messy idea of the LoginOrRegisterModel which may be fine for such a simple example but would get messy very quickly as things got more complex and UIs got refactored with potentially lots of refactoring of models and potentially code as well as just views.</p>
  
  <p>I really get the impression some replacing of the default model binder to have some sort of model binding based on a descriminator and having the controller action working as some sort of command processor such that it would fire off the correct handler based which partial was posted would be better, and resolve the refresh issue that comes from redirection as mentioned by Mystere Man below.</p>