Post JSON data to an MVC controller from a Kendo datasource

By February 28, 2014Uncategorized

The default examples provided by Kendo are an excellent starting point for understanding how to implement it in your project. However, they cannot cover every scenario. One particularly common scenario is the need to send JSON data to fulfill a parameter. The dataType attribute applied to your data source or even your jQuery ajax call determines the format of the data it receives not what it sends. By default both methods send ‘post’ data to a controller as form data and ‘get’ as a querystring value. This is fine for simple requests that contain strings, integers, etc. But what if you want to post a full blown model to a controller as a parameter? Well, again if that model consists of only the aforementioned variable types then sending as form data or a querystring will match it to your model just fine. In many scenarios your model won’t just consist of simple variable types but perhaps instead it contains a List of a model you’ve defined. In this case the data sent as form data will not bind to your model in your controller. The resolution is to post the data as JSON to your action controller for all intended actions. Here’s an outline of a few quick changes you need to make to get this to work.

Let’s assume you have an action in your controller that accepts a custom object type we’ll call FilteredParameter. FilteredParameter in this case consists of an integer and a list of integers.

//The action
public JsonResult CreateMyItems(FilteredParameter fparam)
{
    var results = MyData.GetItems(fparam);
    return Json(results, JsonRequestBehavior.AllowGet);
}

public class FilteredParameter
{
    public List<int> IDs { get; set; }
    public int TargetID { get; set; }
}

Now you might frequently see the transport section of your kendo datasource set up similar to this.

transport: {
     create: {
         url: "/api/CreateMyItems",
         data: { TargetID: idOfSomething, IDs: arrayOfIDs},
         dataType: "json"
     }
 }

However in our case here we will see the following passed to our controller action. You can see this in your browser by using the developer console (usually f12) and looking at the network tab, filtering to see your requests, and selecting the request from the list. By default the above example would send data in a querystring like so:

TargetID=10&IDs%5B%5D=1&IDs%5B%5D=2&IDs%5B%5D=3

If you post the data it would look like so:

Form Data:
TargetID: 10
IDs[]: 1
IDs[]: 2
IDs[]: 3

The result for both would be a FilteredParameter with null for IDs but 10 for a TargetID, which makes sense if you look at how the data is formatted above.

The resolution is to add a few things to our datasource. Some of you might be thinking or have already tried to just use the JSON.stringify, or the kendo equivelant, on the data. However that will result in an Invalid JSON primitive. Instead we can approach the situation like this.

Inside the method of your datasource’s transport definition add the acceptable content types and a ‘Post’ declaration if you haven’t already. This resolution won’t work if it’s left as a ‘Get’ type. For information about the difference and how it might apply to your project check this article out.

create: {
    url: "/api/CreateMyItems",
    data: { TargetID: idOfSomething, IDs: arrayOfIDs},
    contentType: "application/json",
    accepts: "application/json",
    type: 'POST',
    dataType: "json"
},

Under the same transport declaration add a parameter mapping. In this case it’s important to note that the parameter in your javascript must match the parameter in your controller action.

parameterMap: function (data, type) {
    if (type == "create" && data) {
        return JSON.stringify({ fparam: data });
    }
}

The resulting ‘post’ made to the controller will populate the FilteredParameter object with both the integer value and the list of integer values. You can see the difference in the header of your request as the data is sent as a json payload.

Request Payload:
{fparam: {TargetID: 10, IDs: [1,2,3]}}

 This works for all of the transport methods including, update, create, delete, and read. Enjoy!

The following two tabs change content below.
  • Thanks, Patrick – this was really helpful fixing a tricky issue with my datasource. Works perfectly now!

  • Zakayo Thuku

    Hey, AM having problems saving the state of my page and the values
    therein, so that when i refresh the page, the values i selected would be
    still selected, but in my case, when i refresh the page or go to
    another page then come back, the values i selected are no longer
    selected, forcing me to start the selection again, anyone please help me
    around this