title: How do you send a complex object with an ajax post method to c# controller?
body: <p>I'm trying to send a complex javascript object to a mvc controller post method.
  I receive a BadRequest response every time I run the method. It won't let me debug with visual studio, only with the web developer tools. I checked with fiddler to see that my JSON object seems to be in the same order as the View Model. Could anybody please help me with this?
  I am using Asp.Net Core 1.0. Please let me know if I need to provide any more information.</p>
  
  <p>Here's is my view model:</p>
  
  <pre><code>public class RouteViewModel
      {
          public RouteViewModel() { }
          public List&lt;CheckpointViewModel&gt; Checkpoints { get; set; }
          public int TotalDistance { get; set; }
      } 
   public class CheckpointViewModel
      {
          public decimal Latitude { get; set; }
          public decimal Longitude { get; set; }
      }
  </code></pre>
  
  <p>The logic to compile the object is as follows:</p>
  
  <pre><code>function createObject() {
      var routeModel = { Checkpoints: [] ,TotalDistance:totalDistance};
      for (var i = 0; i &lt; markersOrders.length; i++) {
          var latlng = markersOrders[i].getPosition();
          var Checkpoint = {
              'Latitude': latlng.lat(),
              'Longitude': latlng.lng()
          };
          routeModel.Checkpoints.push(Checkpoint);
      }
      return JSON.stringify(routeModel);
  }
  </code></pre>
  
  <p>Here's my ajax method:</p>
  
  <pre><code>function saveRoute() {
      var apiUrl = location.origin + "/map/AddRoute";
      $.ajax({
          method: "POST",
          url: apiUrl,
          contentType: "application/json;charset=utf-8",
          data: (createObject())
      }).done(function (msg) {
          alert("Data saved: " + msg);
      }).error(function(msg){alert("Error: "+ msg)});
  }
  </code></pre>
  
  <p>The controller that is receiving the post is as follows: </p>
  
  <pre><code>        [HttpPost]
          [ValidateAntiForgeryToken]
          public IActionResult AddRoute([FromBody]RouteViewModel route)
          {
              RouteViewModel newRoute = route;
              if (ModelState.IsValid)
              {
                  _context.AddRoute(newRoute.Checkpoints, newRoute.TotalDistance);
                  _context.SaveRoute();
                  return RedirectToAction("SavedRoutes");
              }
              else
              {
                  return BadRequest(ModelState);
              }
          }
  </code></pre>
  
  <p>Here is my RAW Post:</p>
  
  <pre><code>POST https://localhost:44343/map/AddRoute HTTP/1.1
  Host: localhost:44343
  Connection: keep-alive
  Content-Length: 290
  Accept: */*
  Origin: https://localhost:44343
  X-Requested-With: XMLHttpRequest
  User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36
  Content-Type: application/json;charset=UTF-8
  Referer: https://localhost:44343/Map/Map
  Accept-Encoding: gzip, deflate, br
  Accept-Language: en-US,en;q=0.8
  Cookie: .AspNetCore.Antiforgery.4IsE6XVGxQo=CfDJ8HmVr1mwBStLrOG_4RXM-sje_SmjZYd-GboPG5E19rchqlC61XsNEwa7yOgIySC-U63iTH6cD0ggwqwmwdPJOibPKrxlctls_a_b3wmPvai80vYUx6j0Lckfn24GBf7X_xZhAl3eac892j7YDJWa9Oc; .AspNetCore.Identity.Application=CfDJ8HmVr1mwBStLrOG_4RXM-shK66Uthf3kfJJezCs7HCTztr-seJHxVj8l5MS66u4EWd72NEXUjebAIfHIxFZvHjZzjiQSVfLCxdHnmcsbYWXgGAmaA_sBjdimNQXnPAC-NMtp_fDeTCPJEoB1lBy1hl-GFQaAJdRzVrcc7OchWTSBVZ9jdHmm0htNyChcJ8BUCczH8FhVnPeFzlCM_reR8u2vsQrOxY_ZmczdUQ_mqCmTVLGDdRRJwHLhuafrZ2mmAXq1iDzQhprtv98qAx2zM4TSoAOBKoeALq_Oa2n1SDvFMMtGseDB1mLsj-LkPlKhcCmtB14kwDRctvOtxOqCbQTfFjhLlc5405_dccQjWJ3mITtn1ss3x1aHUP-pHHzFX9ZhusQ1-IqV4pPDs12c1q2B5Uz0qEOHaUByVEE5bKpzklTT2kxNW1V81aGMMmwbi9zFkuh9nUFnQmGCqf5VXSx-FTm-UDWZgyMnK0JpG7K4cpiSeycv9sOeP1qUlz-P28RXLhCvqYAX3FIccRfoQMf63tU5OfVhu1bhRdV_NQALhBpku9nrxFyxxECe5WRc4It-kCLiaOQBlYa9bewb80QiWIS-wHNDY5vVcdAkd2D5
  
  {"Checkpoints":[{"Latitude":-34.004057732693184,"Longitude":25.649633891880512},{"Latitude":-34.00313273259371,"Longitude":25.65392542630434},{"Latitude":-34.001425013635725,"Longitude":25.653367526829243},{"Latitude":-34.00019756942711,"Longitude":25.650320537388325}],"TotalDistance":919}
  </code></pre>
  
  <p>As advised by @<a href="https://stackoverflow.com/users/1184056/kiran-challa">Kiran Challa</a> I collected my modelstate errors in the controller and wrote it to Output window like this: </p>
  
  <pre><code>        [HttpPost]
          [ValidateAntiForgeryToken]
          public IActionResult AddRoute([FromBody]RouteViewModel route)
          {
              RouteViewModel newRoute = route;
              if (ModelState.IsValid)
              {
                  _context.AddRoute(newRoute.Checkpoints, newRoute.TotalDistance);
                  _context.SaveRoute();
                  return RedirectToAction("SavedRoutes");
              }
              else
              {
                  //Getting errors
                  var errors = ModelState.Values.SelectMany(v =&gt; v.Errors);
                  Debug.WriteLine("Errors found: "+ errors+"\nEnd Errors found");
                  return BadRequest(ModelState);
              }
          }
  </code></pre>
  
  <p>In my output window when I trigger the controller, all I receive is this: </p>
  
  <pre><code>Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException: The required antiforgery header value "RequestVerificationToken" is not present.
     at Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgery.&lt;ValidateRequestAsync&gt;d__9.MoveNext()
  --- End of stack trace from previous location where exception was thrown ---
     at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
     at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
     at Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.ValidateAntiforgeryTokenAuthorizationFilter.&lt;OnAuthorizationAsync&gt;d__3.MoveNext()
  Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Warning: Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.ValidateAntiforgeryTokenAuthorizationFilter'.
  Microsoft.AspNetCore.Mvc.StatusCodeResult:Information: Executing HttpStatusCodeResult, setting HTTP status code 400
  Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 37.4837ms 400 
  </code></pre>