2

I'm trying to pass a List of objects back to my controller, but the List is null if/when it gets to the controller. Here is what I'm doing:

Controller Action Signature

[HttpGet]
public ActionResult SaveSpec(IEnumerable<DpvItemLiteVm> alarms){}

View Model

public class DpvItemLiteVm
    {
        public string Location { get; set; }
        public string Program { get; set; }
        public string DeviceType { get; set; }
        public string PartName { get; set; }
        public string RoutineId { get; set; }
        public string FtrName { get; set; }
        public string FtrAttCode { get; set; }
        public decimal LowVal { get; set; }
        public decimal HiVal { get; set; }
        public decimal? TargetVal { get; set; }
    }

And the View

var alarms = [];

$('#featureSpecGrid tr').each(function () {
     var $tds = $(this).find('td');
     var target = $tds.eq(4).text() === '' ? null : parseFloat($tds.eq(4).text());
     var temp = {
          Location: location,
          Program: program,
          DeviceType: device,
          PartName: part,
          RoutineId: routine,
          FtrName: $tds.eq(0).text(),
          FtrAttCode: $tds.eq(1).text(),
          LowVal: parseFloat($tds.eq(2).text()),
          HiVal: parseFloat($tds.eq(3).text()),
          TargetVal: target
     };
     alarms.push(temp);
});

//alarms = JSON.stringify({ 'alarms': alarms });

//console.log(alarms);

$.ajax({
     type: 'GET',
     cache: false,
     contentType: 'application/json',
     url: '/Dpv/SaveSpec',
     data: alarms
}).done(function (partialViewResult) {
     $('#statusMsg').html(partialViewResult);
}).always(function(result) {
     console.log(result);
});

I've tried this answer, this answer, and this answer (to name a few); if I use JSON.stringify (as some of the answers suggest) I get a 404 response. I've also tried using a List instead of IEnumerable, making my View Model smaller (location, program, device, part, and routine are the same for each item being passed back) and setting up the AJAX accordingly (returns a 404 error). If I do manage to make it back to the controller, the List is null.

Here's a sample of the payload if I stringify it: {"alarms":"Location":"ABC123","Program":"1A2B","DeviceType":"Device","PartName":"Part1","RoutineId":"ABC456","FtrName":"Feature1","FtrAttCode":"CodeA","LowVal":-1.01,"HiVal":1.01,"TargetVal":null}

And if I don't stringify:

[object Array] 0 Location:"ABC123" Program:"1A2B" DeviceType:"Device" PartName:"Part1" RoutineId:"ABC456" FtrName:"Feature1" FtrAttCode:"CodeA" LowVal:-1.01 HiVal:1.01 TargetVal":null 1

Can anyone help?

user3517375
  • 91
  • 2
  • 14

1 Answers1

3

When using contentType: 'application/json', you need to send data as the JSON string so that model binder will be able to map it.

You should be sending complex data via POST method, not GET. GET method is fine for sending small lean-flat view model with few properties. These will be send as query string by the $.ajax method. In your case, your data is not a flat-lean view model. So you should use POST as the method so that $.ajax will send the data in request body.

I also recommend you to use the Url.Action helper method to generate the correct relative url to the action method.

var urlToSave="@Url.Action("SaveSpec","Dpv")";
// use urlToSavefor the ajax call 

$.ajax({
     type: 'POST',       
     contentType: 'application/json',
     url: urlToSave,
     data: JSON.stringify(alarms)
}).done(function (partialViewResult) {
     $('#statusMsg').html(partialViewResult);
}).always(function(result) {
     console.log(result);
});

Also make sure your aciton method is POST

[HttpPost]
public ActionResult SaveSpec(IEnumerable<DpvItemLiteVm> alarms)
{
    // to do : return something
}

Now the model binder will be able to read the request body and map it to the IEnumerable<DpvItemLiteVm> parameter you have.

Shyju
  • 214,206
  • 104
  • 411
  • 497
  • This is what I needed; works like a charm now. That's good to know about `POST`; I've always used `@using(Html.BeginForm(){}` to pass large amounts of data back to the controller for processing, but I'm adding to an existing code base and using a `form` would have been much more difficult to get it to work. Thanks for the help! – user3517375 Nov 09 '17 at 20:37