title: Posting multiple model Objects with Ajax in .NET core
body: <p>I've been wracking my brain and the various SO posts on the same topic (see <a href="https://stackoverflow.com/questions/13597361/jquery-ajax-and-posting-multiple-complex-objects-to-asp-net-mvc-controller">JQuery Ajax and Posting multiple complex objects to asp.net MVC Controller</a>, <a href="https://stackoverflow.com/questions/31148599/passing-multiple-objects-to-my-controller">Passing multiple objects to my controller</a>, etc) but I'm having trouble getting multiple objects to post from an Ajax call to my controller (.NET Core). I believe I have set up my code like this tutorial has (<a href="http://www.dotnetcurry.com/aspnet-mvc/1253/multiple-model-objects-input-controller-action-methods" rel="nofollow noreferrer">http://www.dotnetcurry.com/aspnet-mvc/1253/multiple-model-objects-input-controller-action-methods</a>) and have also used suggestions from here: <a href="http://andrewlock.net/model-binding-json-posts-in-asp-net-core/" rel="nofollow noreferrer">http://andrewlock.net/model-binding-json-posts-in-asp-net-core/</a> to no avail.</p>
  
  <p>The issue: I can only get the first, but not the second, object to bind. </p>
  
  <p>Controller method:</p>
  
  <pre><code>[HttpPost]
  [ValidateAntiForgeryToken]
  public IActionResult Apply(ApplicationInfoViewModel info, SRAgreementViewModel agreement)
  {
       if(ModelState.IsValid){
       //do stuff. ModelState.IsValid returns false here.
       }
  }
  </code></pre>
  
  <p>Here's my JS:</p>
  
  <pre><code>$(function () {
      $("#ApplyBAOForm").submit(function (e) {        
          var jsonObj = $('#ApplyForm').serialize();
          var srFormJsonObj = $('#SRForm').serialize();
  
          $.ajax({
              url: "ApplyBao/Apply",
              datatype: "json",
              contentType: "application/json; charset=utf-8",
              data: { info: jsonObj, agreement: srFormJsonObj },
              type: "POST"
          }).done(function (result) {
              console.log("Apply success: " + result);
              if (result.type === "success") {
                   //hooray  
              }
              else {
                  //boo                
              }
          });
  
      });
  });
  </code></pre>
  
  <p>So this is a bit of an odd situation: there's actually data from two separate forms here. The SRform data is validated prior to submitting the ApplyForm (it is in a modal), but is only actually submitted for persistence with the ApplyForm. The resulting serialized objects from both forms appears to be correct and similar (jsonObj and srFormObj). </p>
  
  <p>When I hit the ModelState.IsValid statement, it returns false because the SRAgreement object is essentially null (with default values). However, the ApplicationInfoViewModel object correctly shows data from the form. </p>
  
  <p>Other things I've tried: </p>
  
  <ul>
  <li>combining the two objects into one view model (both child objects
  wound up being null?) </li>
  <li>Adding the SRAgreement object as a child of the ApplicationInfo object; the SRAgreement object was null. </li>
  <li>adding [FromBody] as described by the blog postfrom Andrew Lock, this jsut resulted in an HTTP 415 unsupported media type response</li>
  </ul>
  
  <p>There's likely a better way to do this, but I would think that what I'm attempting to do should be doable. </p>
  
  <p>Thanks! </p>
  
  <p><strong>EDIT 2:</strong></p>
  
  <p>It appears that I can't even bind one JSON object. I've got to be missing something simple. I've pared it down to just submitting one of the two objects as JSON as such:</p>
  
  <pre><code>[HttpPost]
  [ValidateAntiForgeryToken]
  public IActionResult Apply([FromBody] ApplicationInfoViewModel info) 
  {
      if (ModelState.IsValid)
      {
       // do stuff
      }
   }
  </code></pre>
  
  <p>JS: </p>
  
  <pre><code>$("#ApplyBAOForm").submit(function (e) {
          e.preventDefault();
  
          var jsonObj = ConvertFormToJSON($("#ApplyBAOForm"));
          var srFormJsonObj = ConvertFormToJSON($("#SRForm"));
          var obj2 = JSON.stringify({ info: jsonObj });
  
          $.ajax({
              url: "ApplyBao/Apply",
              datatype: "json",
              contentType: "application/json; charset=utf-8",
              data: obj2,
              //data: JSON.stringify(jsonObj),
              type: "POST"
          }).done(function (result) {
              console.log("Apply success: " + result);
  
              }
              else {
                  //show some error message or something                
              }
          });        
      });
  });
  </code></pre>
  
  <p>Now the request looks like this:</p>
  
  <pre><code>Request URL:http://localhost:19194/ApplyBao/Apply
  Request Method:POST
  Status Code:400 Bad Request
  Remote Address:[::1]:19194
  Response Headers
  view parsed
  HTTP/1.1 400 Bad Request
  Server: Kestrel
  X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNccmdiMDA3M1xEb2N1bWVudHNcYmFvYWRtaW5pc3RyYXRpb25cc3JjXEJBT0FkbWluaXN0cmF0aW9uXEFwcGx5QmFvXEFwcGx5?=
  X-Powered-By: ASP.NET
  Date: Thu, 12 Jan 2017 21:59:27 GMT
  Content-Length: 0
  Request Headers
  view parsed
  POST /ApplyBao/Apply HTTP/1.1
  Host: localhost:19194
  Connection: keep-alive
  Content-Length: 580
  Pragma: no-cache
  Cache-Control: no-cache
  Accept: */*
  Origin: http://localhost:19194
  X-Requested-With: XMLHttpRequest
  User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
  Content-Type: application/json; charset=UTF-8
  Referer: http://localhost:19194/ApplyBao
  Accept-Encoding: gzip, deflate, br
  Accept-Language: en-US,en;q=0.8
  Cookie: .AspNetCore.Antiforgery.l7Q8WGuEtq8=CfDJ8K9L5D4kNnBPrb3_9Hu-w57rjjf751Qf9eh-z57qWmtMA53AB6FXsZ7pbIuLkdP2F6GjA7TGl0Tz7TfACCn3QeFt_uC-BgsYnk3Nd8z0ZA0c90XVEA90NnQOnmVFRu_KF2_2DXV89Jur84rMa-s26nQ
  Request Payload
  view parsed
  {"info":{"HearAboutUsSelectedId":"137","FirstName":"Ron","LastName":"Bud","MiddleName":"","MaidenName":"","Email":"r@test.com","BirthDate":"1900-01-15","Phone":"123456","Fax":"","Street":"1234","City":"Denton","State":"TX","Zip":"12345","Country":"USA","SelectedExamTrack":"BCaBA","SelectedTranscriptSendMethod":"requested","Degree":"Education","SraId":"00000000-0000-0000-0000-000000000000","__RequestVerificationToken":"CfDJ8K9L5D4kNnBPrb3_9Hu-w56wPCITEDVZQo7flUIB70Pu4Q81TlRXa_oI4t8Bleou6l45oHHmUFrKusKofA6Gey-uSgKP7M3L-DrawE1TVJnrDsULHlnOE9ngg9LuyFK6-cylBJ-91h5fmaico-0yrZE"}}
  </code></pre>
  
  <p>The JSON now looks like a proper JSON object, but it seems my princess is in another castle. Is there something else in the pipeline that I'm missing to enable this?</p>
  
  <p>UPDATE:</p>
  
  <p>I finally figured it out. Turns out that the AntiForgery token was causing the 
  request to fail, as mentioned here:
  <a href="https://stackoverflow.com/questions/38191079/posting-complex-json-to-asp-net-core-controller">POSTing complex JSON to ASP.NET Core Controller</a>
  Removing that for the moment is allowing me to move forward. Thanks!</p>