Passing Parameters to $.ajax ASMX web service using POST

Passing Parameters to $.ajax ASMX web service using POST

timwilsontimwilson Posts: 7Questions: 0Answers: 0
edited November 2012 in General
Allan,

This started as a question, but now I have resolved the issue and wanted to post my findings for others that need to pass parameters to an ASMX web service using POST. With the time I spent fighting this before getting the ah-ha moment I figured it might help others save time.

Further, based on what I have found it may be something that you could take into account as an option for the fnServerParams option of passing parameters.

Problem:

I am using an ASMX web service so I need to use POST to call the web service. This also returns the JSON in .d further requiring me to finally end up using fnServerData with a $.ajax call to get the data from my web service correctly. After much work I finally got this code to work to do that and it has worked rock solid in the past weeks as I have been developing my application:

[code]
"fnServerData": function (sSource, aoData, fnCallback, oSettings) {
oSettings.jqXHR = $.ajax({
"dataType": 'json',
"contentType": "application/json; charset=utf-8",
"type": "POST",
"url": sSource,
"data": aoData,
"success": function (json) {
fnCallback(json.d);
}
});
},
[/code]

Everything worked fine until I needed to start tweaking my data by passing parameters. I knew this would be necessary but I waited till I got everything working as I wanted to figuring this would be an easy addition. Was I ever wrong!! (because of the ASMX web service I might add)

Based on the documentation and the forums the way to do this with DataTables was by either adding this to the fnServerData block:

[code]
aoData.push({ "name": "UserID", "value": "1" });
[/code]

or by adding an fnServerParams block like this:

[code]
"fnServerParams": function ( aoData ) {
aoData.push({"name": "UserID", "value": "1" });
},
[/code]

but neither one worked for me no matter what I did. I tried everything I could think of but even though the browser was acting like all was good I was not getting the response I needed.

I started to dig with the Firebug console to finally find what my issue was. When using these options the POST source looked like this:

[code]
UserID=1
[/code]
or
[code]
UserID=1&Type=admin
[/code]

aka: a URL encoded string

The problem is that an ASMX web service requires the POST source to be a JSON string like this:

[code]
{'UserID':'1'}
[/code]
or
[code]
{'UserID':'1','Type':'admin'}
[/code]

I kept getting the error "Invalid JSON primitive: UserID." because of the above POST source and my search results on the DataTables Forums came up empty. I did eventually find a lot of good information concerning this exact problem thanks to Dave Ward at Encosia. This post helped me understand the problem and ultimately the work around.

http://encosia.com/asmx-scriptservice-mistake-invalid-json-primitive

In short from the above post, the reason this is happening is because the JavaScript object literal being supplied to $.ajax()’s data parameter. jQuery serializes $.ajax()’s data parameter using the URL encoded scheme, regardless of what Content-Type is specified.

As seen in this code:

[code]
"fnServerParams": function ( aoData ) {
aoData.push({"name": "UserID", "value": "1" });
},
"fnServerData": function (sSource, aoData, fnCallback, oSettings) {
oSettings.jqXHR = $.ajax({
"dataType": 'json',
"contentType": "application/json; charset=utf-8",
"type": "POST",
"url": sSource,
"data": aoData,
"success": function (json) {
fnCallback(json.d);
}
});
},
[/code]

The trick explained in the above post is to pass the data parameter as a JSON string instead of a JavaScript object literal. When the data parameter is a JSON string jQuery won’t attempt to perform any further transformation, and the JSON string will be unimpeded as it is passed to the ASMX ScriptService.

However..........

This trick will not work with the fnServerParams (or even the old way with just aoData.push). I tried using the above trick and putting single quotes around the data like so:

old:
[code]
aoData.push({"name": "UserID", "value": "1" });
[/code]

new:
[code]
aoData.push('{"name": "UserID", "value": "1" }');
[/code]

but that didn't work and just errored out.

It would be awesome if Allan added this option, but I needed a solution now. I kept looking at my $.ajax call and finally I asked myself, why can't I just pass the data to the ASMX web service like I do when I call other ASMX web services in my application.

I tried it and it just worked!

The following code is how I ended up passing parameters to my ASMX web service. I left the commented out code to show how the two "normal" ways to do it with DataTables is done.

[code]
//"fnServerParams": function ( aoData ) {
// aoData.push({"name": "UserID", "value": "1" });
//},
"fnServerData": function (sSource, aoData, fnCallback, oSettings) {
// aoData.push({ "name": "UserID", "value": "1" });
oSettings.jqXHR = $.ajax({
"dataType": 'json',
"contentType": "application/json; charset=utf-8",
"type": "POST",
"url": sSource,
// "data": aoData,
"data": JSON.stringify({ UserID: "1" }),
"success": function (json) {
fnCallback(json.d);
}
});
},
[/code]
This discussion has been closed.