Search code examples
c#ajaxasp.net-mvckendo-datasourcekendo-ui-grid

Error "Invalid JSON primitive: models." on Kendo Grid datasource while passing model to controller


Getting error while implementing Kendo Grid inline edit CRUD. When I add a new record and update it, I receive response code 500 with error:

I believe the problem is coming from parameterMap. What is the correct way to pass the model to the controller in Kendo?

Invalid JSON primitive: models.

What are the models?

Source Code:

$(document).ready(function () {
        var baseUrl = "/SomeUrl",
            dataSource = new kendo.data.DataSource({
                transport: {
                    read: {
                        url: baseUrl + "/GetAccolades?profileId=" + @profileId,
                        type: "GET",
                        dataType: "json"
                    },
                    create: {
                        url: baseUrl + "/AddAccolade",
                        type: "POST",
                        dataType: "json",
                        contentType: "application/json",
                    },
                    update: {
                        url: baseUrl + "/UpdateAccolade",
                        type: "PUT",
                        dataType: "json",
                        contentType: "application/json",
                    },
                    delete: {
                        url: baseUrl + "/DeleteAccolade",
                        type: "DELETE",
                        dataType: "json"
                    },
                    parameterMap: function (options, operation) {
                        if (operation !== "read" && options.models) {
                            alert(kendo.stringify(options.models));
                            return { models: kendo.stringify(options.models) };
                        }
                    }
                },
                batch: true,
                schema: {
                    model: {
                        id: "ProfileAccoladeID",
                        fields: {
                            ProfileAccoladeID: { editable: false, nullable: false },
                            ProfileID: { editable: false, nullable: false, defaultValue: @profileId  },
                            Years: { type: "string" },
                            Name: { type: "string" },
                            Level: { type: "string" },
                            Event: { type: "string" },                              
                        }
                    }
                }
            });

        $("#accolades-grid").kendoGrid({
            dataSource: dataSource,
            pageable: false,
            height: 550,
            toolbar: ["create"],
            columns: [
                { field: "Years", width: "150px" },
                { field: "Name", title: "Name", width: "150px" },
                { field: "Level", title: "Level", width: "150px" },
                { field: "Event", title: "Event", width: "450px" },                    
                { command: ["edit", "destroy"], title: " ", width: "250px" }],
            editable: "inline"
        });
    });
</script>

Controller method:

    [HttpPost]
    public JsonResult AddAccolade(ProfileAccolade accolade)
    {
        using (var db = new XXXEntities())
        {
            if (accolade != null)
            {
                var newAccolade = new ProfileAccolade()
                {
                    ProfileID = accolade.ProfileID,
                    Years = accolade.Years,
                    Name = accolade.Name,
                    Level = accolade.Level,
                    Event = accolade.Event
                };
                db.ProfileAccolades.Add(newAccolade);
                db.SaveChanges();

                return Json(new { Success = true });
            }
            else
            {
                return Json(new { Success = false, Message = "Error occured" });
            }
        }
    }

How do I fix this error?

Update:

By removing contentType: "application/json", the error Invalid JSON primitive: models. is gone. However, the controller does not get the model.

Any ideas to fix this?


Solution

  • The problem originated by usage of contentType: "application/json" inside both transport.create and transport.update part of kendo.data.DataSource. Since both operations use AJAX call (i.e. jQuery.ajax() method), the contentType setting affects how type of request body will send.

    By setting "application/json" content type, the request body will treated as JSON content, but actually transport.parameterMap returns URL encoded version containing models and formatted JSON string as key-value pair (KVP). This is why "Invalid JSON primitive" error occurs, because URL encoded format is not same as JSON format.

    If you wish to keep "application/json" setting for AJAX call, add JSON.stringify method to convert URL encoded format of models as JSON data:

    parameterMap: function (options, operation) {
        if (operation !== "read" && options.models) {
            return JSON.stringify({ models: kendo.stringify(options.models) });
        }
    }
    

    However if you want to send parameterMap as default content type (application/x-www-form-urlencoded), just remove all contentType definitions to set it back:

    dataSource = new kendo.data.DataSource({
         transport: {
             read: {
                 url: baseUrl + "/GetAccolades?profileId=" + @profileId,
                 type: "GET",
                 dataType: "json"
             },
             create: {
                 url: baseUrl + "/AddAccolade",
                 type: "POST",
                 dataType: "json"
             },
             update: {
                 url: baseUrl + "/UpdateAccolade",
                 type: "PUT",
                 dataType: "json"
             },
             delete: {
                 url: baseUrl + "/DeleteAccolade",
                 type: "DELETE",
                 dataType: "json"
             },
             parameterMap: function (options, operation) {
                 if (operation !== "read" && options.models) {
                     alert(kendo.stringify(options.models));
                     return { models: kendo.stringify(options.models) };
                 }
             }
         },
         // other DataSource definitions
    });
    

    Reference:

    kendo.data.DataSource (Kendo UI Documentation)