Eden Ridgway's Blog

.Net and Web Development Information

  Home :: Contact :: Syndication  :: Login
  105 Posts :: 1 Stories :: 78 Comments :: 3 Trackbacks

Search

Article Categories

Archives

Post Categories

Development

General

I've only just started investigating ExtJS and what it can possibly provide over and above the ASP.Net AJAX framework. The first thing I wanted to do was use the ASP.Net AJAX JavaScript webservice proxies instead of the expected REST style services. Unfortunately I ran into several problems and ended up using a slightly different approach to what I found on the ExtJS forums. Let me quickly outline the problem. In ExtJS they use a store wrapper for their data which is assigned to a grid panel. This store object may also know how to fetch external data that it needs via a proxy, which is defined like so:

var ds = new Ext.data.Store({
    proxy: 
new Ext.data.HttpProxy(
         {
          url: 
'/WebServices/OrderService.asmx/GetOrders',
          params: { userId: getUserId(), day: 
new Date() }
         }),
    reader: 
new Ext.data.JsonReader(
        {
           id: 
'WorkDoneId'
        
},
    ...
})
;

Unfortunately, try as I might to get this to call my web service (and I tried quite a few different approaches), I would get errors returned by the service. It may have been that unlike all the examples I had seen on the web, like Daniel Larson's my service calls actually needed to send parameters through to the service. One was to add additional properties to the ScriptMethod attribute on the web service like so:

[ScriptMethod(ResponseFormat ResponseFormat.Json, UseHttpGet = true, XmlSerializeString = false)]

I also tried using the ASPProxy class found on this forum post. This also didn't work properly and there were a few minor irritations with the code. It all seemed pretty silly since with the ScriptManager service reference I had a client side proxy that I knew would work properly. So I created the AspWebServiceProxy object that would allow you to simply pass in a reference to the client side web service proxy object and method and use that:

AspWebServiceProxy = function (conn)
           {
              AspWebServiceProxy.superclass.constructor.call(
this);
              
Ext.apply(this, conn);
           
};

Ext.extend(AspWebServiceProxy, Ext.data.DataProxy, 
{
     load : 
function (params, reader, callback, scope, arg)
            {
               
var userContext {
                                    callback: callback, 
                                    reader: reader, 
                                    arg: arg, 
                                    scope: scope
                                 }
;
               
               var 
proxyWrapper = this;
               
               
//Handles the response we get back from the web service call
               
var webServiceCallback = function(response) 
                                        { 
                                            proxyWrapper.loadResponse(response, userContext)

                                        
}
               
               
var serviceParams [];
               
               
//Convert the params into an array of values so that they can be used in the call (note assumes that the properties on the object are in the correct order)
               
for (var property in params)
               {
                  serviceParams.push(
params[property]);
               
}
               
               
//Add the webservice callback handlers
               
serviceParams.push(webServiceCallback);
               
serviceParams.push(this.handleErrorResponse);
               
               
//Make the actual ASP.Net web service call
               
this.webServiceProxyMethod.apply(this.webServiceProxy, serviceParams)
            
},
            
     handleErrorResponse : 
function(response, userContext, methodName)
                           {
                              
alert("Error while calling web service method:" + methodName + "\n" + response.get_message());
                           
},
 
     loadResponse : 
function (response, userContext, methodName)
                    {
                        
var result userContext.reader.readRecords(response);
                        
userContext.callback.call(userContext.scope, result, userContext.arg, true);
                    
}
        
})
;

So if you had an ASP.Net web service script reference on your page, like this:

<asp:ScriptManager ID="PageScriptManager" runat="server">
    
<Services>
        
<asp:ServiceReference Path="/WebServices/OrderService.asmx" InlineScript="false" />
    </
Services>
</asp:ScriptManager>

to use the proxy class one would change the code at the start of the article to look like this:

 var ds = new Ext.data.Store({
    proxy: 
new AspWebServiceProxy(
         {
          webServiceProxy: Example.OrderService,
          webServiceProxyMethod: Example.OrderService.GetOrders,
          params: {userId: getUserId(), day: 
new Date()}
         }),
    reader: 
new Ext.data.JsonReader(
        {
           id: 
'WorkDoneId'
        
},
    ...
})

I'm sure that I'll be tweaking the AspWebServiceProxy object over time as I discover its short comings, but at least it is a decent start and is hopefully useful to others as well. One of my concerns are the manner in which the attributes on the extraParams object must be specified in the same order as the web service method parameters. I did it this way to keep it consistent with all the other examples I had seen where they used an object as opposed to an array. I may change this, but I like the fact that with the current approach the parameter value pairs are obvious.

Update - 2 Nov 2007: Changed the service options of extraParams to params. So now one can use dataStore.load({params: {userId: 4, day: new Date()} }) to load data after the creation of the data source.
posted on Tuesday, October 09, 2007 7:19 AM

Feedback

# re: Using ASP.Net AJAX WebServices (ScriptServices) in ExtJS 10/30/2007 10:21 PM Eric Hauser
Nice post. This approach worked great for me.

In .NET 3.5 (if you get a chance to use it), you can use its built it POX features to access the URLs and get JSON directly by doing:

[OperationContract]
[WebGet(
BodyStyle = WebMessageBodyStyle.Bare,
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
UriTemplate = "/GetAll")]
IList<DataObject> GetAll();

Then you can access the method directly by going to:

/Service.svc/GetAll

# re: Using ASP.Net AJAX WebServices (ScriptServices) in ExtJS 10/31/2007 8:23 PM Jonathan
I'm very new to this so please bear with my stupid question:

how can this work??
webServiceProxy: Example.OrderService,
webServiceProxyMethod: Example.OrderService.GetOrders,

it has NO idea what Example is and it's not an object right? If i have a service at http://localhost:2563/Service1.asm with MethodName() in the webservice, how would i plug webServiceProxy and webServiceProxyMethod correctly in there?

Thank you!


# re: Using ASP.Net AJAX WebServices (ScriptServices) in ExtJS 11/1/2007 7:27 AM Eden Ridgway
Hi Jonathon

I've updated my post to include an example of how to add a web service reference to the page using the ASP.Net AJAX framework. When you do that the framework will generate a fully qualified client side proxy (with "namespace"). So in my example Example would be the namespace and OrderService the name of the service class object on the client. So in your example Say Service1.asmx lived in a project with a default namespace of MyProject, you would plug MyProject.Service1 into the webServiceProxy value and MyProject.Service1.MethodName into the webServiceProxyMethod.

Hope that helps

# re: Using ASP.Net AJAX WebServices (ScriptServices) in ExtJS 11/1/2007 7:35 AM Eden Ridgway
Hi Eric

Thanks for the info, I may give it a try later.

Regards
Eden

# re: Using ASP.Net AJAX WebServices (ScriptServices) in ExtJS 11/1/2007 4:39 PM Jonathan
Thank you! I had figured that out actually, and implemented it as such. Now, i get something returned from the Ajax enabled .NET service _however_, when i hit this line in the code:
var result = userContext.reader.readRecords(response);

in the loadResponse, it bombs with Microsoft JScript runtime error: 'prototype' is null or not an object...

I can see it's returning whatever im returning from the service (i tried a string, xml, to no avail) but this line dies for a reason that escapes me...


# re: Using ASP.Net AJAX WebServices (ScriptServices) in ExtJS 11/1/2007 4:41 PM Jonathan
Btw, i DID try replacing JsonReader on the Ext.Data with XmlReader -- to no avail...

# re: Using ASP.Net AJAX WebServices (ScriptServices) in ExtJS 11/1/2007 5:07 PM Jeff Lewis
The ExtSharp project @ http://extsharp.googlecode.com lets you use ExtJs from C# (translated to JS via Script#). The SVN version is tied to ExtJs 2.0 beta 1.

It makes it real easy to use this stuff. We've got translated a lot of the samples that ExtJs has on their site as well.

# re: Using ASP.Net AJAX WebServices (ScriptServices) in ExtJS 11/2/2007 6:23 AM Eden Ridgway
Hi Jonathon

I'm afraid I'm not entirely sure what your problem is. Is there any way you could put together an example on the web that I can take a look at?

# re: Using ASP.Net AJAX WebServices (ScriptServices) in ExtJS 11/4/2007 7:18 PM Jonathan
Eden, what i meant was: in my ExtJS script, I have a data store fed via JsonReader -- I cant figure out how to return JSON from the script service in C#, however I am able to return an XmlDocument which feeds a ExtJS XmlReader just fine.
I dont particularly give a crap about JSON at this point I'm happy to return XML but it's frustrating to me. Either way this has nothing to do with your code.

This ExtJS is a nightmare to use and learn but that's life :) thank god for posts like yours!

Thanks!

# re: Using ASP.Net AJAX WebServices (ScriptServices) in ExtJS 11/24/2007 3:45 PM Ian McMillan
Hi, to start with I couldn't get the proxy to call a web service without an error. However, I found out that you need

to make sure you have the directive in the web service code thus:

using System.Web.Script.Services;



And you have to make sure that you put the "[ScriptService]" property at the top of the class as shown below.

[WebService(Namespace = "localhost")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class Service : System.Web.Services.WebService
{


The proxy works very well (thankyou!) now and calls my webservice which returns a JSON string using the Newtonsoft

library for C# to serialize it. For example:

string output = JavaScriptConvert.SerializeObject(people);

where people is a list of person objects.



List<Person> people = new List<Person>();

people.Add(new Person(50, "Fred", "Bloggs"));
people.Add(new Person(30, "John", "Smith"));
people.Add(new Person(26, "Andrew", "Darling"));
people.Add(new Person(24, "Xavier", "FrenchBloke"));
people.Add(new Person(5, "Mark", "Almond"));
people.Add(new Person(6, "Cameron", "Diaz"));

Here is the Person class...


public class Person
{
public int P_ID;
public string firstName;
public string lastName;
public Person(int P_ID, string firstName, string lastName)
{
this.P_ID = P_ID;
this.firstName = firstName;
this.lastName = lastName;
}
}

Now when called the web service returns this in the firebug console:



"[{\"P_ID\":50,\"firstName\":\"Fred\",\"lastName\":\"Bloggs\"},{\"P_ID\":30,\"firstName\":\"John\",\"lastName

\":\"Smith\"},{\"P_ID\":26,\"firstName\":\"Andrew\",\"lastName\":\"Darling\"},{\"P_ID\":24,\"firstName

\":\"Xavier\",\"lastName\":\"FrenchBloke\"},{\"P_ID\":5,\"firstName\":\"Mark\",\"lastName\":\"Almond

\"},{\"P_ID\":6,\"firstName\":\"Cameron\",\"lastName\":\"Diaz\"}]"


Now here's the problem I'm having, I can see no way of getting my JsonReader, XmlReader or any other reader in EXT to

work, the object is returned and each identifier is there such as "P_ID", "firstName", "Lastname" but there is NO data

in JSON object so when I try to fill my EXT form with data it just gets filled with nulls...

Here is my JsonReader, datastore etc:




var fieldMap = new Ext.data.Record.create([
{name : 'P_ID'},
{name : 'firstName'},
{name : 'lastName'}

]);

var dataStore = new Ext.data.Store({
proxy: new AspWebServiceProxy(
{
webServiceProxy: Service,
webServiceProxyMethod: Service.GetEmployee

}),reader: new Ext.data.JsonReader({},fieldMap)


Here is where I load the store:

dataStore.on('load', function(){
var employee = dataStore.getAt(0).data; // get record data
form_employee.setValues ({
PerId: employee.P_ID,
fName: employee.id,
lName: employee.id

})

});


This appears in Firebug when I watch it...


New watch expression...
this Object data=[315] baseParams=Object paramNames=Object
employee Object
P_ID ""
firstName ""
lastName ""


Now I am rendering the form and I am calling load(); for the datastore.

This is driving me nuts, I'm sorry to be such a pain with something probably so simple but I'm just learning EXt so

it's a steep curve for me. Can anyone help me please? What am I doing wrong??

Thanks in anticipation.

Ian








# Using ScriptServices Serialization 11/25/2007 10:07 AM Eden Ridgway
Hi Ian

Just as a word of reassurance you are not alone in your pain with ExtJS. I have found the framework to be somewhat fickle largely due to the fact that they have not put in the effort to validate calls to the framework methods and object constructors. Complex layouts can also be particularly frustrating and time consuming.

With all that being said, is there any particular reason why you are using the Newtonsoft library to serialize the object to a JSON string instead of just letting the ASP.Net AJAX framework do it for you? By the way you can also use System.Web.Extension.JavaScriptSerializer to serialize objects to a string for you.

You could just expose the object as you would normally via the web service as opposed to exposing a string. All you need to get it to work is create a parameterless constructor for you Person class and change your web method signature. In that way the ASP.Net AJAX client side framework will deserialize the object for you. This is part of your problem as the JsonReader.readRecords() method expects an array of objects and not a string. The simplest solution is to simply change your web service method to look something like this:

[WebMethod]
public List<People> GetPeople()

If you are still struggling I have created a little example application that demonstrates the solution, which you can download from here: http://www.ridgway.co.za/demos/ExtJSScriptServiceExample.zip

Hope that helps.

# re: Using ASP.Net AJAX WebServices (ScriptServices) in ExtJS 11/25/2007 3:50 PM Ian McMillan
Eden,

Thankyou so much! That's a very simple and elegant solution to my problem.

I was using the Newtonsoft library because I was told that it is the only one that deals with complex objects. I will be needing to serialize objects that contain objects at some point but I guess that isn't a problem now!

I have to say, I really like EXTJS BUT the learning curve is almost vertical and well, without firebug I would have been completely at a loss!

I am SO grateful to you, you are an absolute star! This has given me a good start. I just sort of hit a brick wall but thanks for explaining why my solution wouldn't work; it was driving me nuts!

Regards,

Ian



# re: Using ASP.Net AJAX WebServices (ScriptServices) in ExtJS 12/4/2007 6:26 AM Victor
Does anybody has a VS2005 Solution Working to share?
Thanx

# re: Using ASP.Net AJAX WebServices (ScriptServices) in ExtJS 12/4/2007 9:01 AM Eden Ridgway
Hi Victor

The example at http://www.ridgway.co.za/demos/ExtJSScriptServiceExample.zip will run in Visual Studio 2005. All you need to do is unzip the files and use File -> Open -> Web Site and then navigate to the code folder to open it in VS.Net.

It is a pretty basic example based on Ian McMillan's problem scenario, but hopefully it will give you what you need.

Eden

# re: Using ASP.Net AJAX WebServices (ScriptServices) in ExtJS 12/13/2007 4:06 AM victor
thanks will try it. But I already installed orca (.net3.5), im testing it.

# re: Using ASP.Net AJAX WebServices (ScriptServices) in ExtJS 1/23/2008 12:30 AM Mike
Thanks a bunch for the script, very useful. Forgive me, I am new to .NET and ExtJS and have searched for the answer to this question all day. Using your script, how would I go about passing though parameters to the web service? For instance pagination values...? Thanks again,

# re: Using ASP.Net AJAX WebServices (ScriptServices) in ExtJS 1/24/2008 9:28 AM Eden Ridgway
Hi Mike

Once you've assigned the proxy to your ExtJS data store you get the data store to invoke your proxy like this:

dataStore.load({params: {page: 1, day: new Date()} })

You may also want to take a look at the same I referred to in an earlier comment.

Hope that helps.

# re: Using ASP.Net AJAX WebServices (ScriptServices) in ExtJS 1/24/2008 11:08 PM Mike
Eden,

Thanks so much for your reply. Maybe I am just not understanding your explanation correctly or didn't explain myself well. Assuming that the params: {} does pass values to the webservice, how do I then retrieve the values in the wevservice so I can use them to process the specified query? Hope that makes sense... I am needing the values to go from the javascript, through the proxy, and then be available for use in the webservice so the webservice can know what data to return. Sorry for my confusion :-)

# re: Using ASP.Net AJAX WebServices (ScriptServices) in ExtJS 1/28/2008 7:08 PM Mike
Nevermind, I was using it correctly but running into another JS error. Thanks again for the code, works great :-)

# re: Using ASP.Net AJAX WebServices (ScriptServices) in ExtJS 2/5/2008 5:20 PM Mohammed Osman
The grid is loading fine by

dataStore.load({params:{i_Params:paramXML,start:0, limit:10}});

But then when we do paging , the grid doesn't pass "i_Params" to the server and the request fails...

do you have any idea about this

Comments have been closed on this topic.