PDA

View Full Version : How to send parameters to ASP.NET JSON WebService



jchau
14 Jul 2008, 7:24 AM
I have been trying to hook up ExtJS to read from an ASP.NET webservice for almost a week now. I have searched through this forum and the web and found lots of great examples. Seems like this is a frustrating topic for many people.

So far, everything works fine if the webservice doesn't have any parameters. The webservice returns JSON fine and I have a gridpanel that displays the data correctly using JsonReader. But if I add a parameter to the webservice, Fiddler is showing an error returned by the webservice.

Response


{"Message":"Invalid JSON primitive: username.","StackTrace":" at System.Web.Script.Serialization.JavaScriptObjectDeserializer.DeserializePrimitiveObject()\r\n at System.Web.Script.Serialization.JavaScriptObjectDeserializer.DeserializeInternal(Int32 depth)\r\n at System.Web.Script.Serialization.JavaScriptObjectDeserializer.BasicDeserialize(String input, Int32 depthLimit, JavaScriptSerializer serializer)\r\n at System.Web.Script.Serialization.JavaScriptSerializer.Deserialize(JavaScriptSerializer serializer, String input, Type type, Int32 depthLimit)\r\n at System.Web.Script.Serialization.JavaScriptSerializer.Deserialize[T](String input)\r\n at System.Web.Script.Services.RestHandler.GetRawParamsFromPostRequest(HttpContext context, JavaScriptSerializer serializer)\r\n at System.Web.Script.Services.RestHandler.GetRawParams(WebServiceMethodData methodData, HttpContext context)\r\n at System.Web.Script.Services.RestHandler.ExecuteWebServiceCall(HttpContext context, WebServiceMethodData methodData)","ExceptionType":"System.ArgumentException"}

Request:


username=johndoe


I believe this is because HttpProxy is sending the parameter in a wrong format. Because I specify the contenttype to be application/json;charset=utf-8, the webservice is probably expecting 'username:johndoe'. The contenttype setting is needed for the webservice to serialize the result as JSON. How do I get HttpProxy to change the way it sends the parameter?

Note: I can make everything work if the webservice returns XML instead of JSON since I dont have to set the contenttype any more. However, I would like to learn how to get JSON working.

devnull
14 Jul 2008, 8:27 AM
I dont know asp.net at all and quite frankly by your description of it i dont want to :)
It would probably be in your interest to find out exactly how it wants to receive params, and if that isnt documented then move on to something else that actually works (hint, php).

jchau
14 Jul 2008, 11:08 AM
I think I do know how it wants to receive params. The issue is how do I get ExtJS to send the parameters that way? Instead of sending 'username=johndoe', I want ExtJS to send 'username:johndoe'.

Gunmen
14 Jul 2008, 12:20 PM
I'm not sure if you need a webservice at all.

You might consider using an ashx file. Then do your asp.net stuff.

Read query string parameters:
string username = context.Request.Form["username"];

Or send JSON formated text:
Please see this (http://james.newtonking.com/projects/json/help/ReadingWritingJSON.html) page.

Hope this helps.

jchau
14 Jul 2008, 12:45 PM
Unfortunately, using ASP.NET webservice is required. Here's an article on how this issue is resolved when using jQuery and ASP.NET webservice.

http://encosia.com/2008/06/05/3-mistakes-to-avoid-when-using-jquery-with-aspnet-ajax/

The solution for jQuery is to wrap their param value with quotes so jQuery will treat it as a string. jQuery data = ExtJS baseParams.



data: "{'fname':'dave', 'lname':'ward'}",



Why can't I do the same with ExtJS?

Gunmen
14 Jul 2008, 1:07 PM
Unfortunately, using ASP.NET webservice is required. Here's an article on how this issue is resolved when using jQuery and ASP.NET webservice.

http://encosia.com/2008/06/05/3-mistakes-to-avoid-when-using-jquery-with-aspnet-ajax/

The solution for jQuery is to wrap their param value with quotes so jQuery will treat it as a string. jQuery data = ExtJS baseParams.



Why can't I do the same with ExtJS?

Hmm, I don't know. Looks like you combine a lot of things... asp.net, c#, javascript, jQuery, AJAX.net... I should take a look at json.net (http://james.newtonking.com/projects/json-net.aspx) (and skip ajax.net/jquery).

jchau
14 Jul 2008, 2:09 PM
Figured it out with the help of another ExtJS user. Had to set jsonData instead of baseParams.

devnull
14 Jul 2008, 2:15 PM
you still apparently havent done the research or dont have enugh of a background in web technologies to understand the problem...
does it want a GET query string? how about POST data? serialized JSON in the POST body?
A query string has a very fixed format, and even microsoft cant change that (though you can bet they try) so GET params have to always be param=value.
the jquery hints that it may be the latter, but its hard to say for sure without some documentation from microsoft. which knowing them may well be very hidden...

jchau
14 Jul 2008, 2:47 PM
you still apparently havent done the research or dont have enugh of a background in web technologies to understand the problem...
does it want a GET query string? how about POST data? serialized JSON in the POST body?
A query string has a very fixed format, and even microsoft cant change that (though you can bet they try) so GET params have to always be param=value.
the jquery hints that it may be the latter, but its hard to say for sure without some documentation from microsoft. which knowing them may well be very hidden...

I dont think you understand the issue I had originally. This doesn't have anything to do with the query string. The webservice expects the request to be in json format because the contenttype is set to json. I just needed a way to make the ajax calls from extjs send the parameter in json format, which I was able to do by setting jsonData instead of params in the config. Everything is working great now. The webservice is getting its json parameters and sending back json data to the client.

nyster
9 Sep 2008, 5:28 AM
Hi Jchau,

I am also having the same problem. So can you please show me the sample how you solved using jsonData?

Thanks!

cducker
15 Dec 2008, 3:35 PM
To further clarify how jchau got this to work, he used the jsonData config parameter of the HttpProxy object instead of using the baseParams of the Data.Store object.

For some reason, the jsonData config parameter is not specified in their API documentation for the HttpProxy object. Actually neither is the url or method config parameter.

Here's an example of what I mean:


var moduleStore = new Ext.data.Store({
proxy : new Ext.data.HttpProxy({
jsonData : '{"organizationId" : ' + data.OrganizationId + '}',
url : '/Service1.svc/GetOrganization',
method : 'POST'
}),

reader : new Ext.data.JsonReader({
root : 'd',
id : 'ModuleId',
fields : ['ModuleId', 'Name', 'Enabled']
})

});

jchau
15 Dec 2008, 3:51 PM
For anyone trying to get ExtJS to work with ASP.NET, I highly recommend using Coolite instead.

johnosterlund
3 Mar 2009, 12:52 AM
To further clarify how jchau got this to work, he used the jsonData config parameter of the HttpProxy object instead of using the baseParams of the Data.Store object.

For some reason, the jsonData config parameter is not specified in their API documentation for the HttpProxy object. Actually neither is the url or method config parameter.

Here's an example of what I mean:


var moduleStore = new Ext.data.Store({
proxy : new Ext.data.HttpProxy({
jsonData : '{"organizationId" : ' + data.OrganizationId + '}',
url : '/Service1.svc/GetOrganization',
method : 'POST'
}),

reader : new Ext.data.JsonReader({
root : 'd',
id : 'ModuleId',
fields : ['ModuleId', 'Name', 'Enabled']
})

});


This works as long as you don't use prebuilt functionality around the store, for example the paging mechanism for grids. It's really annoying to use Ext with ASP.NET webservices :( The problem with the parameters seems to occur when changing the content-type to "application/json; charset=utf-8" (as ASP.NET require us to do). When changing the content type the parameters are sent as a query string instead of HTTP parameters. For example:


Content-type: text/html; charset=utf-8
Parameters (seen in Firebug POST-tab):
password: myPassword
username: myUsername

Content-type: application/json; charset=utf-8
Parameters (seen in Firebug POST-tab):
username=myUsername&password=myPassword
Anyone having a clue or solution on this problem?

Animal
3 Mar 2009, 4:45 AM
To further clarify how jchau got this to work, he used the jsonData config parameter of the HttpProxy object instead of using the baseParams of the Data.Store object.

For some reason, the jsonData config parameter is not specified in their API documentation for the HttpProxy object. Actually neither is the url or method config parameter.

Here's an example of what I mean:


var moduleStore = new Ext.data.Store({
proxy : new Ext.data.HttpProxy({
jsonData : '{"organizationId" : ' + data.OrganizationId + '}',
url : '/Service1.svc/GetOrganization',
method : 'POST'
}),

reader : new Ext.data.JsonReader({
root : 'd',
id : 'ModuleId',
fields : ['ModuleId', 'Name', 'Enabled']
})

});


The docs say



HttpProxy( Object conn )

Parameters:

conn : Object

an Ext.data.Connection object, or options parameter to Ext.Ajax.request. If an options parameter is passed, the singleton Ext.Ajax object will be used to make the request.

Animal
3 Mar 2009, 4:47 AM
This works as long as you don't use prebuilt functionality around the store, for example the paging mechanism for grids. It's really annoying to use Ext with ASP.NET webservices :( The problem with the parameters seems to occur when changing the content-type to "application/json; charset=utf-8" (as ASP.NET require us to do). When changing the content type the parameters are sent as a query string instead of HTTP parameters. For example:


Content-type: text/html; charset=utf-8
Parameters (seen in Firebug POST-tab):
password: myPassword
username: myUsername

Content-type: application/json; charset=utf-8
Parameters (seen in Firebug POST-tab):
username=myUsername&password=myPassword
Anyone having a clue or solution on this problem?

A query string is what POSTed parameters look like.

johnosterlund
3 Mar 2009, 5:25 AM
A query string is what POSTed parameters look like.

Yes, but in the case of working with ASP.NET webservices the paramaters has to be sent as json (not totally sure about this) as mentioned in this thread. The problem comes when you are working with PagingToolbar for example. PagingToolbar adds its parameters (start and limit) to the parameters of the related store as ordinary paramaters NOT json. From Ext.PagingToolbar source:


doLoad : function(start){
var o = {}, pn = this.paramNames;
o[pn.start] = start;
o[pn.limit] = this.pageSize;
if(this.fireEvent('beforechange', this, o) !== false){
this.store.load({params:o});
}
},
This will result in a POST like:


start=0&limit=20&otherKeyValuePairs...
But ASP.NET webservice would like it to be:


{"start":0,"limit":20,otherKeyValuePairs...}
How could I accomplish this?

Animal
3 Mar 2009, 6:00 AM
I see. So you want the Store to be able to send its params as jsonData?

Perhaps you should subclass HttpProxy to make WebserviceProxy, and override the load method to send the params as jsonData insteab of params.

johnosterlund
3 Mar 2009, 6:29 AM
I see. So you want the Store to be able to send its params as jsonData?

Perhaps you should subclass HttpProxy to make WebserviceProxy, and override the load method to send the params as jsonData insteab of params.

Yes, exactly!

I have never subclassed in Ext before but now is probably a good time to give it a try. Thank you!

johnosterlund
4 Mar 2009, 12:34 AM
Finally I got it working, this is my solution to it:

Overriding the Ext.data.HttpProxy.load()-method:


Ext.ux.AspNetHttpProxy = Ext.extend(Ext.data.HttpProxy, {
load: function(params, reader, callback, scope, arg) {
// JSON-encode parameters because ASP.NET requires that
params = Ext.util.JSON.encode(params);
Ext.ux.AspNetHttpProxy.superclass.load.call(this, params, reader, callback, scope, arg);
}
});
Overriding the Ext.data.JsonReader.read()-method:


Ext.ux.AspNetJsonReader = Ext.extend(Ext.data.JsonReader, {
read: function(response) {
var json = response.responseText;
var o = Ext.util.JSON.decode(json);
o = o.d; // Take care of the extra wrapper that ASP.NET adds
if (!o) {
throw { message: "JsonReader.read: Json object not found" };
}
return this.readRecords(o);
}
});
Usage:


var store = new Ext.data.Store({
proxy: new Ext.ux.AspNetHttpProxy({
url: "WebService.asmx/MyWebMethodName",
headers: { 'Content-Type': 'application/json; charset=utf-8' }
}),
reader: new Ext.ux.AspNetJsonReader({
root: 'rows',
totalProperty: 'results',
id: 'id',
fields: [
{ name: 'id', type: 'int' },
{ name: 'name', type: 'string' }
]
}),
remoteSort: false // Turn off remote sorting
});

store.baseParams = { name: "John", start: 0, limit: 10 };
store.load();
I hope this could be helping someone else in the same situation!

MarcusGarvey'sGhost
1 May 2009, 3:35 AM
IF (and this is a big if) it is an option for you, you can just set the request method to

requestMethod: 'GET'

Then make sure you decorate your web service method with the attribute

[ScriptMethod(UseHttpGet= true)]

I have done this because all calls to my webservice methods are validated anyway, so it it does not matter if i'm using get or post method.

Another option would just be for Micro$oft to release the web service serializer code so that we can just change or provide an override for the method, donít hold your breadth

yurchi
21 May 2009, 2:29 AM
If you don't wan't use custom Json reader in store you can simply override method:

Ext.data.JsonReader.override({
read : function(response) {

var json = response.responseText;
var o = Ext.util.JSON.decode(json);

// fix for ASP.NET JavaScript serialyzer
if (o.d)
o = o.d;

if (!o) {
throw {
message : "JsonReader.read: Json object not found"
};
}
return this.readRecords(o);
}
});

yurchi
21 May 2009, 2:32 AM
To get values from request on store.load(...) per pagging in asp.net can be used next logic:

int lStart = 0, lLimit = 14;
if (HttpContext.Current.Request.QueryString.Count > 0)
{
string lStrStart = HttpContext.Current.Request.QueryString["start"];
string lStrLimit = HttpContext.Current.Request.QueryString["limit"];
int.TryParse(lStrStart, out lStart);
int.TryParse(lStrLimit, out lLimit);
}

Crockford
29 Nov 2010, 5:41 AM
Finally I got it working, this is my solution to it:

Overriding the Ext.data.HttpProxy.load()-method:


Ext.ux.AspNetHttpProxy = Ext.extend(Ext.data.HttpProxy, {
load: function(params, reader, callback, scope, arg) {
// JSON-encode parameters because ASP.NET requires that
params = Ext.util.JSON.encode(params);
Ext.ux.AspNetHttpProxy.superclass.load.call(this, params, reader, callback, scope, arg);
}
});
Overriding the Ext.data.JsonReader.read()-method:


Ext.ux.AspNetJsonReader = Ext.extend(Ext.data.JsonReader, {
read: function(response) {
var json = response.responseText;
var o = Ext.util.JSON.decode(json);
o = o.d; // Take care of the extra wrapper that ASP.NET adds
if (!o) {
throw { message: "JsonReader.read: Json object not found" };
}
return this.readRecords(o);
}
});
Usage:


var store = new Ext.data.Store({
proxy: new Ext.ux.AspNetHttpProxy({
url: "WebService.asmx/MyWebMethodName",
headers: { 'Content-Type': 'application/json; charset=utf-8' }
}),
reader: new Ext.ux.AspNetJsonReader({
root: 'rows',
totalProperty: 'results',
id: 'id',
fields: [
{ name: 'id', type: 'int' },
{ name: 'name', type: 'string' }
]
}),
remoteSort: false // Turn off remote sorting
});

store.baseParams = { name: "John", start: 0, limit: 10 };
store.load();
I hope this could be helping someone else in the same situation!

Hi John, I have searched a lot for a solution to this issue.
I have the same problem and I tried your solution very excited. I liked the way you solved it.
But...

It seems to not solve the problem because the parameters are not sent as json and I get the usual error.
The contenttype is set to application/json.
name.","StackTrace":" in System.Web.Script.Serialization.JavaScriptObjectDeserializer.DeserializePrimitiveObjectDo you have some hints about?
Thanks

custjcy
24 Mar 2011, 12:49 AM
.Hi, Crockford:

I find it works by overloading dorequest method in my computer:


Ext.ux.AspNetHttpProxy = Ext.extend(Ext.data.HttpProxy, {
doRequest: function(action, rs, params, reader, cb, scope, arg) {
// JSON-encode parameters because ASP.NET requires that
params = Ext.util.JSON.encode(params);
Ext.ux.AspNetHttpProxy.superclass.doRequest.call(this, action, rs, params, reader, cb, scope, arg);
}
});