0

I'm able to pass form data to an ASP.Net web service from an ajax script and receive a JSON object in response, works great. When I make the same call, with the same parameters in JQ Grid I receive an "Invalid web service call" or "Invalid JSON primitive" in response.

I believe this is fairly close to the following post, I've applied the recommendations (as well as those from many other posts) but with no success. JQGrid - Cannot call ASP.NET WebMethod but can with Ajax

The following Ajax code is successful, it passes the forms parameters to the web service and retrieves the results in the JSON format.

Ajax Javascript code: this code works it's the JQ Grid (further below) thats the problem

<script language="JavaScript">
    function populateResults() {
    var arForm = $("#searchForm").serializeArray();

    $.ajax({
      type: "POST",
      url: "./WebService/Service.asmx/doSearch",
      data: JSON.stringify({ formVars: arForm }),
      contentType: "application/json",
      dataFilter: function(data) {
        var msg = eval('(' + data + ')');
        if (msg.hasOwnProperty('d'))
          return msg.d;
        else
          return msg;
      },
      success: function(msg) {
        // This will now output the same thing 
        //  across any current version of .NET.
        //console.log(msg.foo);
      }
    });
    };

    </script>

Web Service:

[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string doSearch(NameValue[] formVars)
{...

The Problem: The following is my JQ Grid code that fails:

<script type="text/javascript">
    function populateResults() {
        var arForm = $("#searchForm").serializeArray(); 
        var searchParams = JSON.stringify({ formVars: arForm });

        var grid = $("#tblResults");
        grid.jqGrid({
            url: "./WebService/Service.asmx/doSearch",
            ajaxGridOptions: { contentType: 'application/json; charset=utf-8' },
            data: searchParams,
            dataType: 'json',
            dataFilter: function(data) {
                var msg = eval('(' + data + ')');
                alert(msg.d);

                if (msg.hasOwnProperty('d'))
                  return msg.d;
                else
                  return msg;
            },
            mtype: 'POST',
            colNames:['Exam Date','Type','Name','UR Number','Pathology Type','Result Date','Modality', 'Results'],
            colModel:[
                {name:'resExamDate',index:'resExamDate', editable:false, width:120},
                {name:'resType',index:'resType', editable:false, width:60},
                {name:'name',index:'name', editable:false, width:120},
                {name:'urnumber',index:'urnumber', width:65, sorttype:'int'},
                {name:'resPathologyType',index:'resPathologyType', editable:false, width:120},
                {name:'resResultDate',index:'resResultDate', editable:false, width:120},
                {name:'resModality',index:'resModality', editable:false, width:170, cellattr: function (rowId, tv, rawObject, cm, rdata) { return 'style="white-space: normal;"'}},
                {name:'results',index:'results', editable:false, width:240, cellattr: function (rowId, tv, rawObject, cm, rdata) { return 'style="white-space: normal;"'}}
            ],
            rowNum:10,
            rowList:[5,10,20],
            pager: '#pager',
            sortname: 'surname',
            viewrecords: true,
            sortorder: "desc",
            height: "100%",
            processData: false,  //jquery will stringify again apparently: https://stackoverflow.com/questions/6471759/invalid-web-service-call-missing-value-for-parameter
            serializeGridData: function (postData) { return JSON.stringify(postData);   },
            jsonReader: { 
                total: "total",
                page: "page",
                records: "records",
                root: "rows",
                id: "id",
                cell: "cell",
                repeatitems: false
            }
        });
    }
    </script>

In Firebug I receive:

Post
{"_search":false,"nd":1338180778103,"rows":10,"page":1,"sidx":"surname","sord":"desc"}

Response
{"Message":"Invalid web service call, missing value for parameter: \u0027formVars\u0027.","StackTrace":"   at System.Web.Script.Services.WebServiceMethodData.CallMethod(Object target, IDictionary`2 parameters)\r\n

Or if I comment out the "serializeGridData:" line (I think I'm serializing it twice or something so I tried commenting it out), I get:

Post:
    _search=false&nd=1338180203206&rows=10&page=1&sidx=surname&sord=desc

Response:
    {"Message":"Invalid JSON primitive: _search.","StackTrace":"   at System.Web.Script.Serialization.JavaScriptObjectDeserializer.DeserializePrimitiveObject()\r\n ......

Any solid ideas on why it doesn't work? I've spent days trying to get this to work this way. Although I can get it to work by doing an Ajax call and storing the data in a variable and setting that to the JQ Grid, I need direct web service calls from JQ GRid to be working for filtering and other things...

thanks in advance :)

Edit: - Using JQ Grid v4.3.2 - JSON data being sent to the Web Service has been validated using http://jsonlint.com/ (this is the variable "searchParams" in the javascript code above)

Community
  • 1
  • 1
xander
  • 53
  • 1
  • 8

3 Answers3

2

What you use inside of {} (see /*here*/) of the call

grid.jqGrid({/*here*/});

are jqGrid parameters or jqGrid options. It's wrong to use dataFilter here because jqGrid will just ignore the option. In the same way jqGrid don't know dataType option and it ignores dataType: 'json'. The default value of datatype (be careful with the case of letters) is 'xml'. Because JSON response from the server are wrong XML file you will get the error.

In the same way data parameter of jqGrid will by used in another way. You should use postData parameter instead. It's important to understand that you should create jqGrid with the code like grid.jqGrid({/*here*/}); once. So if you want that on paging, sorting or filtering the data the current values from the form "#searchForm" will be send to the server you should define formVars as function. See the answer for more details. If you use mtype: 'POST' then it will be probably easy to add formVars property inside of serializeGridData callback.

So you should rewrite your current code to about the following:

$(function () {
    var grid = $("#tblResults");
    grid.jqGrid({
        url: "./WebService/Service.asmx/doSearch",
        ajaxGridOptions: { contentType: 'application/json; charset=utf-8' },
        serializeGridData: function (postData) {
            // extend the parameter which will be send to the server
            postData.formVars = $("#searchForm").serializeArray();
            // serialize the parameters as JSON string
            return JSON.stringify(postData);
        },
        datatype: 'json',
        mtype: 'POST',
        colNames:['Exam Date','Type','Name','UR Number','Pathology Type','Result Date','Modality', 'Results'],
        colModel:[
            {name:'resExamDate',index:'resExamDate', width:120},
            {name:'resType',index:'resType', width:60},
            {name:'name',index:'name', width:120},
            {name:'urnumber',index:'urnumber', width:65},
            {name:'resPathologyType',index:'resPathologyType', width:120},
            {name:'resResultDate',index:'resResultDate', width:120},
            {name:'resModality',index:'resModality', width:170,
                cellattr: function () {
                    return ' style="white-space: normal;"'
                }},
            {name:'results',index:'results', width:240,
                cellattr: function () {
                    return ' style="white-space: normal;"'
                }}
        ],
        rowNum: 10,
        rowList: [5, 10, 20],
        pager: '#pager',
        sortname: 'surname',
        viewrecords: true,
        sortorder: "desc",
        height: "100%",
        jsonReader: {
            root: function (obj) { return obj.d; },
            page: function () { return 1; },
            total: function () { return 1; },
            records: function (obj) { return obj.d.length; }
        }
    });
});

Additionally it seems that your server part don't implement paging of data. If it ignores all standard jqGrid parameters (rows,page,sidx,sord) you should confider to increase the value of rowNum to rowNum: 10000 for example, remove rowList and other pager information (see the documentation): pgbuttons: false, pginput: false. Additionally you can use

serializeGridData: function () {
    return JSON.stringify({formVars: $("#searchForm").serializeArray()});
}

In the case jqGrid will send only formVars to the server.

Community
  • 1
  • 1
Oleg
  • 220,925
  • 34
  • 403
  • 798
  • Thanks so much for the response Oleg, it worked! :) I can now see the POST data and response from the web service, so thank you very very much :). I will post my full code up on here so it might help others too. – xander May 29 '12 at 03:08
  • I still have 1 issue though, the data is not displaying on the grid which I think is from an incorrect jsonReader configuration. Returning obj.d returns 'undefined', an alert of the obj returns: **{"total":"1","page":"1","records":"15","rows":[{"id":"1","cell":["21-Nov-2011 12:57","Radiology","LASTNAME, Firstname","12345","text","22-Nov-2011 08:58","X-Ray Finger Left","text"]},{"id":"2","cell":["....** within Firebug the webservice is returning: **{"d":"{\"total\":\"1\",\"page\":\"1\",\"records\":\"15\",\"rows\":[{\"id\":\"1\",\"cell\":[\"21-Nov-2011 12:57\",\"Radiology\"...** – xander May 29 '12 at 03:13
  • I've tried using jsonReader parameters such as **root: "rows"** or **root: "d.rows"** or **root: function (obj) { return obj.d; }** but none have been successful, do you have any ideas? – xander May 29 '12 at 03:15
  • @xander: Only the response which starts with `{"d":...` shows the real data. One see that you made one typical error in the web service. One have to return *object* from the web wethod. .NET Framework will make serialization to JSON itself. I suppose that you included some manual call of `JavaScriptSerializer` which is wrong. You can fix the problem inside of `beforeProcessing` like `beforeProcessing: function (data) {data.d = $.parseJSON(data.d);}` but it would be better modify your server code instead. Then you can use `jsonReader: { root: "d.rows", page: "d.page", total: "d.total", ...}` – Oleg May 29 '12 at 05:12
  • By the way I've been using **repeatitems: true** given the formatting of the response JSON. – xander May 29 '12 at 05:13
  • @xander: You don't posted the JSON data before, so I included just one suggestion of `jsonReader`. – Oleg May 29 '12 at 05:15
  • ok, thanks again Oleg! I'll try changing that on the server side. – xander May 29 '12 at 05:15
  • That worked Oleg :) problem solved! (I owe you a few beers or whatever it is you drink) I will post the full code up here soon (once I've cleaned it up a bit) to help others. – xander May 29 '12 at 05:38
  • @xander: You are welcome! I'm glad to hear that the problem is solved now. Congratulation! – Oleg May 29 '12 at 05:52
0

you need to include the expected parameter name of the web service like

var grid = $("#tblResults");
        grid.jqGrid({
            url: "./WebService/Service.asmx/doSearch",
            ajaxGridOptions: { contentType: 'application/json; charset=utf-8' },
            data:{u0027formVars: searchParams},

the former code was successful because there the input param name was included

John x
  • 4,031
  • 8
  • 42
  • 67
  • Thanks John, unfortunately that doesn't work. I believe the parameter is included when the JSON object is stringified in the line 'var searchParams = JSON.stringify({ formVars: arForm });' – xander May 28 '12 at 05:28
  • The JSON object (in the variable searchParams) begins with **{"formVars":[{"name":"txtSearchKeywords","value":""},{"name":"radio","value":"and"},.....** etc so it definitely includes the formVars parameter. – xander May 28 '12 at 05:30
0

You need to pass the data like this:

function populateResults() {
var arForm = $("#searchForm").serializeArray();
var formvars = JSON.stringify(arForm);

$.ajax({
  type: "POST",
  url: "./WebService/Service.asmx/doSearch",
  data: "{'formVars':'" + formvars + "'}",
  contentType: "application/json",
  dataFilter: function(data) {
    var msg = eval('(' + data + ')');
    if (msg.hasOwnProperty('d'))
      return msg.d;
    else
      return msg;
  },
  success: function(msg) {
    // This will now output the same thing 
    //  across any current version of .NET.
    //console.log(msg.foo);
  }
});
};
TheGeekYouNeed
  • 7,509
  • 2
  • 26
  • 43
  • Thanks GeekYouNeed, I've tried that and it still fails with **"Invalid web service call, missing value for parameter: \u0027formVars\u0027."** in the response. I believe calling JSON.stringify({ formVars: arForm }) does the same thing as **data: "{'formVars':'" + formvars + "'}"** – xander May 28 '12 at 06:35
  • what is the value of formvars? Can you put it into an alert window and put it here? – TheGeekYouNeed May 28 '12 at 06:53
  • var searchParams = JSON.stringify({ formVars: arForm }); **an alert of search Params:** {"formVars":[{"name":"txtSearchKeywords","value":""},{"name":"radio","value":"and"},{"name":"txtStartDate","value":""},{"name":"txtEndDate","value":""},{"name":"txtPatientFirstName","value":""},{"name":"txtPatientSurname","value":""},{"name":"txtURNumber","value":""},{"name":"ageMin","value":"0"},{"name":"ageMax","value":"120"},{"name":"sex","value":"both"},{"name":"txtDrFirstName","value":""},{"name":"txtDrSurname","value":""},{"name":"txtRequestingLocation","value":""}...max characters of comment reached – xander May 28 '12 at 07:03
  • Does changing the content type to contentType: "application/json; charset=utf-8", help ? – TheGeekYouNeed May 28 '12 at 07:09
  • Also add this to your ajax call dataType: "json", – TheGeekYouNeed May 28 '12 at 07:10
  • I think you're looking at the Ajax code in the top code block which actually works - I just posted it there to show that what I'm using works. The third code block is for the JQ Grid which is what I'm having the problem with. It does include the contentType and the dataType. – xander May 28 '12 at 07:16