Demystifying The Code

REST in WCF – Part III (AJAX Friendly Services, Consuming The Service)

In yesterdays post REST in WCF – Part II (AJAX Friendly Services, Creating The Service), I introduced a starter solution containing a few ASP.NET AJAX client library controls.  The starter solution was stubbed out, awaiting the implementation of an AJAX-Friendly WCF service and the client code to call that service.  I then went through and implemented an AJAX-Friendly service, taking advantage of the webHttpBinding and the enableWebScript endpoint behavior.

In this post I am going to implement the client-side code that consumes our service.  You will remember from the last post that Catalog.aspx (the main page in the application that contains the AJAX controls) had a stubbed out method GetData.  This method is called when the page is initialized.  It is also called when the user navigates between pages of products.  It is here that I need to add the code to call my WCF service. 

 

Registering the Service

Before I go too far, let me back up a minute.  Earlier I noted that I implemented an AJAX-Friendly WCF service, but what does that mean?  Essentially, it means that our service has an endpoint behavior that provides the functionality to create a client-side ajax proxy class that can be used to call our service in a few lines of code.  All we need to do to get this proxy streamed to the browser is to register our service with the ScriptManager.  See below:

<asp:ScriptManager ID="scriptManager" runat="server">
    <Scripts>
        <asp:ScriptReference Path="Controls/Catalog.js" />
        <asp:ScriptReference Path="Controls/HighlightImageBehavior.js" />
        <asp:ScriptReference Path="Controls/ShoppingCart.js" />
        <asp:ScriptReference Path="Controls/LoginStatus.js" />
    </Scripts>
    <Services>
        <asp:ServiceReference Path="~/CatalogService.svc" />
    </Services>
</asp:ScriptManager> 

If you are not familiar with the ScriptManager, it is an ASP.NET control whose responsibility it is to dole out javascript that is required on a page.  If you have worked with some of the ASP.NET AJAX server controls, they communicate to the ScriptManager their script needs.  The ScriptManager then outputs the appropriate script elements.  In the code above, the Scripts node contains 4 references to ASP.NET AJAX client libraries that are specific to the shopping sample application.  They are not related to the topic at hand, that of calling WCF Services.  The section that is important is the Services node.  You will note that this section contains a ServiceReference with the path to CatalogService.svc file (or the address to the service).  What we have essentially done here is to register the AJAX-Friendly service with the ScriptManager. 

By registering the AJAX-Friendly WCF Service with the ScriptManager, we have told the ScriptManager to emit a script element to the page pointing to a HttpHandler that knows how to generate the client proxy.  In order to illustrate this, I am going to simply run the page up into the browser, right-click on the page and choose ‘View Source’.  I scrolled down the page and found the following:

image

 

The Proxy Class

If you want to see the client proxy code (and you should), append CatalogService.svc/jsdebug to the URL to your web.  In my case, the full URL was: http://localhost:50183/ClientStore/CatalogService.svc/jsdebug.  You will then be presented with the following dialog:

image

I saved the proxy to my desktop to a file named proxy.js.  I then dragged proxy.js to my friend Visual Studio.  Here is part of what I saw:

image

The first thing to notice is that the proxy is taking advantage of the ASP.NET AJAX Client libraries.  In these libraries, we ".NETified" JavaScript.  We added the concept of namespaces, classes, and a whole lot more.  If you are interested in more info about the ASP.NET AJAX client libraries, I did a 12 part webcast series, discussing nearly every facet of the implementation.

The second thing to notice is the namespace for the AJAX class is the same as the namespace for the service created in part II.  The last thing I want to discuss is that the GetPatients operation is added to the prototype of the AJAX class (in JavaScript, every object has a prototype and the prototype is the appropriate place to put non-instance-specific members such as methods).  You will notice that the signature largely matches the signature of our service operation.  The difference being that success and failure callback method parameters were added, along with a context parameter.  This is necessary, as the calls will be made asynchronously.  In other words, our service operation was AJAXified.  It is now quite simple to call our service: 1) create an instance of our proxy class and 2) call the GetPatients method on our proxy.  Actually, there are a 3 and 4.  We need to write the callback methods.  Lets illustrate by filling in the code in GetData.

 

Making the Call

One thing you will notice right off when you are creating the instance of your proxy is that VS 2008 gives you IntelliSense support for the proxy class.  See below:

image

Here is the completed GetData code:

// This function calls the GetProductGrouping AJAX method, 
//   using the script proxy 
function GetData() {
    var startIndex = ((currentPage) * pageSize);
    var proxy = new shopping.services.CatalogService();
    proxy.GetProductGrouping(
        startIndex,
        pageSize,
        ProductsReturnedEventHandler,
        ProductsFailedEventHandler,
        null);
} 

What used to take dozens, if not hundreds, of lines of code to do correctly, now takes 2.  When talking about this, I typically discuss the amount of serialization and deserialization code that is abstracted away from us.  If you were to write all of the code yourself, you would have to write the code to serialize the parameters on the client (and the method information if you are using POST) to some format like JSON or XML.  You would then have to write the code to deserialize the parameters on the server, make the call, get the response from the call in the form of a .NET type.  You would then need to serialize the .NET type to JSON or XML (or whatever you choose) and send it back to the client asynchronously.  Lastly, you would need to deserialize the payload on the client to JavaScript.  All of that is taken care of you by the infrastructure.

In part II, I discussed how the ProductsReturnedEventHandler simply gets a reference to an AJAX control, set 2 properties (1 of them to the response payload of our service call), and calls a method to do the DOM injection.  Lets look at the traffic getting sent around with the help of Visual Studio debugging and WebDevHelper.  The first thing I want to show you is what is passed to the callback method after all of the serialization / deserialization code is done.  Notice that the JavaScript type that was passed to the callback is a close representation of the .NET type detailed in part II.  Even the .NET type name is passed in __type.  Take a look:

image

The next thing I want to show you is the actual request and response (with the help of Nikhil’s WebDevHelper):

image

We can also look at the request and response content:

image

 

Manipulating how the Service is exposed

You noticed above that by default, the service is exposed as a POST.  Even most of the liberal RESTafarians frown upon this.  GET is the defacto choice for all fetch operations for most folks.  Further, you will notice that the default representation format (how the data is serialized) is JSON.  What if you do not want JSON, rather you want some form of XML?  As it turns out, these are 2 things you are able to control when using the enableWebScript endpoint behavior.  You are able to control a whole bunch more with the webHttp endpoint behavior.  You will see that in later posts.

In order to control the HTTP Verb for the operation, you can decorate your operation with 1 of 2 attributes:

  • [WebGet] – Sets the HTTP verb to GET (Go figure…)
  • [WebInvoke(Method="..."] – Sets the HTTP verb to any verb other than GET.  However, when using enableWebScript, only POST is supported.  Other verbs are supported with webHttp endpoint behavior.

WebGet and WebInvoke both take a ResponseFormat argument.  You can set it to WebMessageFormat.Xml or WebMessageFormat.Json.  You can see below how I set these preferences:

[OperationContract]
[WebGet(ResponseFormat=WebMessageFormat.Xml)]
public ProductGroupingData GetProductGrouping(int startIndex, int pageSize) 

In order to illustrate the result of these choices, I called this service from a separate page and here are the results in WebDevHelper:

image

 

Conclusion of AJAX-Friendly REST Services

Over the last 2 posts, I implemented an AJAX-Friendly WCF Service and consumed that service with an AJAX client.  So does this service land on the REST continuum, and if so, where?  I believe it meet the criteria of being RESTful.  First of all, it is not using a SOAP packet and that is certainly a start.  When we examine the differing criteria for RESTfulness, we will find that this implementation clearly lands on the LO REST side.  Consider the following:

  • We are only potentially using 2 HTTP verbs, GET and POST.  We have ignored PUT and DELETE altogether.  In a HI REST scenario, one could argue that the VERB would be enough to understand the intent of the call (GET to fetch, PUT to insert or update, DELETE to delete and POST to append – or something like that).  In this case, with our overloaded POST, we have to look in the request to understand the intent of the call.  Verdict -> LO
  • With regard to URI addressability, in our GET, we are using query strings.  Further, this implementation has the feel of an RPC.  Verdict -> LO
  • With regard to representation format, I could go either way.  Although JSON is a standard, it does not speak to the meaning of the data, rather just the grammar.  However, it is a standard.  Also, you could certainly return a standard and accepted XML representation in your service.  Verdict -> Inconclusive.

Please do not misunderstand the above blathering for grading the service.  That is not the case.  I love the AJAX-Friendly implementation.  I just wanted to give you something to chew on with regards to it’s place on the continuum.

In future posts, I will illustrate an implementation that falls further toward the HI end of the continuum.

Until then…

Speak Your Mind

Tell us what you're thinking...
and oh, if you want a pic to show with your comment, go get a gravatar!

Demystifying The Code