Dan
Dan

Reputation: 831

JSON Array is null when passed to MVC Rest interface

I am attempting to pass a JSON object that contains both generic string properties and an array of objects with properties.

The Model Object:

public class Stock
{
    public IEnumerable<Daily> DailyList;
    public string Symbol { get; set; }
    public double PERatio { get; set; }
}

public class Daily
{
    public double EndOfDayPrice { get; set; }
    public int Volume { get; set; }
    public double DayDiff { get; set; }
}

The following is my HomeController code:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    public JsonResult Dump()
    {
        Stock s = new Stock()
        {
            Symbol = "YHOO",
            PERatio = 4.31,
            DailyList = new List<Daily>()
            {
                new Daily {EndOfDayPrice = 4.13, DayDiff = 1.2, Volume = 15000 },
                new Daily {EndOfDayPrice = 4.1, DayDiff = .5, Volume = 1300 }
            }
        };

        return Json(s, JsonRequestBehavior.AllowGet);
    }

    [HttpPost]
    public JsonResult ProcessDataReturned(Stock stock)
    {
        stock = stock;
        // int count = mylist.Length;
        return Json("success");
    }
}

This is my JavaScript on my page:

function calculate(pricelist) {
    var count = 1; //skip first;
    var teststring = { "DailyList": [{ "EndOfDayPrice": 4.13, "Volume": 15000, "DayDiff": 1.2 }, { "EndOfDayPrice": 4.1, "Volume": 1300, "DayDiff": 0.5 }], "Symbol": "YHOO", "PERatio": 4.31 };

    $.post("/home/ProcessDataReturned/", teststring).done(function (data2) { document.write(data2 + "<hr>"); });
    //Tried with the JSON.stringify also.
    $.post("/home/ProcessDataReturned/", JSON.stringify(teststring)).done(function (data2) { document.write(data2 + "<hr>"); });
}

When I go to the controller and watch the value coming over the array of DailyList is always null. The other properties are fine. I have tried to make the Model(C#) to use both IList and IEnumerable for the property.

NEW CODE as suggested by contributors. I am still having the same problem. Array is still empty (not null because I initialize it in the constructor).

    var x = JSON.stringify({ stock: teststring });
    //Other variations I have tried
    //var x = JSON.stringify(teststring);

    $.ajax({
        url: '@Url.Action("ProcessDataReturned", "home")',
        data: x,
        type: 'POST',
        traditional:true,
        contentType: "application/json; charset=utf-8",
        success: function (data) {
            $('#message').html("Reason was updated");}
    });

Solution: Because there were actually multiple pieces wrong I gave credit to each person. Additionally I found one bug on my own. 1. I must use the long form version of the ajax call. ie use $.ajax instead of $.post 2. My model on the server was not set up correctly. I needed to add the "{get;set;}" to the property declaration for the list. Silly mistake on my part and the code below enabled me to see that issue. public class Stock { //public IEnumerable DailyList; //Change this to this (Stupid Mistake): public IEnumerable DailyList {get;set;}; public string Symbol { get; set; } public double PERatio { get; set; } }

Upvotes: 0

Views: 1573

Answers (1)

user3559349
user3559349

Reputation:

Because your collection items are not correctly names with indexers, your need to use ajax() with traditional: true.

var teststring = { "DailyList": [{ "EndOfDayPrice": 4.13, "Volume": 15000, ....}
$.ajax({
  type: 'POST',
  url: '@Url.Action("ProcessDataReturned", "home")', // do not hard code your urls
  traditional: true,
  contentType: "application/json; charset=utf-8",
  data: JSON.stringify({ stock: teststring }),
  ....
})

Note if your javascript object was

{ DailyList[0].EndOfDayPrice: 4.13, DailyList[0].Volume: 15000, ..., DailyList[1].EndOfDayPrice: 4.1, DailyList[1].Volume: 1300, ...}

Then the object would be bound using the $.post() method in your code

Edit

Your Stock class does not have a property for DailyList (its a field) and as a result the default model binder cannot set the values. Change it to a property

public IEnumerable<Daily> DailyList { get; set; }

Upvotes: 1

Related Questions