Demystifying The Code

REST in WCF – Part II (AJAX Friendly Services, Creating The Service)

In yesterday’s post REST in WCF – Part I (REST Overview), I gave a brief overview of REST, putting forth the idea of a continuum of RESTfulness of services, ranging from HI REST to LO REST.  In this post, I am going to illustrate, perhaps the most familiar kind of RESTful WCF service, an AJAX Friendly service.  As we will see, this kind of service will fall on the LO REST side of the continuum.  Now, some people naturally see bigger and higher as necessarily better, therefore discounting the viability of this LO REST implementation.  As you will see in this post, that is not the case.  The AJAX Friendly WCF service is indeed quite powerful and consequently helpful.

A bit of background on the solution

I have a starter solution that has much of the grunt work already complete.  Much of this code was built as part of a 12 part webcast series on our AJAX Client Libraries.  My thought is, what better way to illustrate the power of AJAX Friendly WCF services than to build one on the fly and integrate it with a viable AJAX client application (If you don’t think the sample app I built is viable, check out supersefer, a store implemented in Hebrew that was based on this sample.  The starter solution includes, among other things, 2 ASP.NET AJAX controls: Catalog.js and ShoppingCart.js.  See below how these 2 client control render:

image

The catalog control is of interest to us in this post.  It was designed to accept a specific data structure, representing a page of products, for binding purposes and to raise events when a product was selected or the navigation controls were clicked.  I’ll leave the details of how the catalog control was wired up on the host page (Catalog.aspx) to the webcast series.  What is important to this post is the code below from Catalog.aspx (the page containing the control).  What you will see is a stubbed out method GetData.  This is where we want to make the call to our yet-to-be-implemented WCF service.  We will pass it some information such as the startIndex and the pageSize (we want to return pages of products), as well as the callback methods (for success and failure).  I’ve shown the success callback method here, as well.  The method simply gets a reference to the catalog control ($get is asp.net ajax for referencing a control).  It then sets the index of the current page and sets the productInfo property with the data passed to the callback method, our WCF payload.  Lastly, the method calls a dataBind method on the control.  That method simply does some DOM injection, given the data now stored in productInfo.

image

 

Adding the service

Adding the AJAX Enabled WCF Service is an easy process.  The first step is to use the ‘AJAX-enabled WCF Service’ template to add the service.  To do this, Right-Click on the project (in Solution Explorer) > Choose ‘Add New Item’ > Choose ‘AJAX-enabled WCF Service’ > Name it CatalogService.svc > click ‘Add’.

image

Now, some folks tend to view templates as magic, when in reality they are simply adding specific files and updating others (usually *.config files).  This template does the following (if you follow the steps above):

  1. Adds a CatalogService.svc file to the project root
  2. Adds a CatalogService.cs file in the app_code
  3. Configures the service in the web.config

Examining the files

Lets take a look at each of the files created by the template and discuss briefly:

CatalogService.svc

<%@ ServiceHost
        Language="C#"
        Debug="true"
        Service="CatalogService"
        CodeBehind="~/App_Code/CatalogService.cs" %>

The *.svc file is analogous to the *.asmx file.  If the service is hosted in IIS or WAS, this file acts as the addressable resource.  In other words, the URL to the *.svc is the base address to your service.  There are really to things of interest in this file.  The first is the Service Attribute.  It is set to the CLR type name of the service implementation (You will find this type in the CatalogService.cs file in the app_code directory).  The second interesting attribute is the CodeBehind att that points to the implementation.

You don’t need to do anything with this svc file.  I just wanted to point it out, show you a few details and alert you to the fact that this acts as the base address.

web.config

  <system.serviceModel>
    <behaviors>
      <endpointBehaviors>
        <behavior name="CatalogServiceAspNetAjaxBehavior">
          <enableWebScript />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
    <services>
      <service name="CatalogService">
        <endpoint   address=""
                    behaviorConfiguration="CatalogServiceAspNetAjaxBehavior"
                    binding="webHttpBinding"
                    contract="CatalogService" />
      </service>
    </services>
  </system.serviceModel>

If you are familiar with WCF, you already know that the WCF configuration occurs under the system.serviceModel node.  Here you will see 3 child nodes: behaviors, serviceHostingEnvironment and services. 

  1. Services:  Here you will see that one service has been added, with a name of CatalogService.  The name matches the type name of the implementation.  Under the service node, you will see the endpoint, which contains the ABCs of the service, the address, binding and contract.
    • Address:  You will note that the address is blank.  This is ok, because, as we noted before, the svc file will act as the address.
    • Binding:  The webHttpBinding is the new binding to WCF 3.5 that provides the ability to expose your services RESTfully.  This binding has 2 modes, which are specified by defining the appropriate endpoint behavior (by setting the behaviorConfiguration)
    • Contract:  The contract specifies the functionality the service exposes to the client.  This Attribute is set to a defined service contract.  You can define a service contract by decorating either and interface or a class with a ServiceContract attribute.  Every method decorated with an OperationContract attribute in the interface or class will be exposed as an operation of the service.  It is arguably better practice to use an interface as the service contract, as it separates the contract from the implementation.  What you see here is that this template uses the class approach.  In this case, the interface is inferred (interface inference). 
    • Behavior Configuration: For the webHttpBinding, you need to set this attribute to an endpoint behavior that has a child node of webHttp or enableWebScript.  See below…
  2. Behaviors: are added to the service or service endpoints with the purpose of changing the default behavior of the runtime or add custom extensions.  In this case you will see that the template declared an endpoint behavior named CatalogServiceAspNetAjaxBehavior.  This behavior has an enableWebScript element as its child.  enableWebScript is one of two possible endpoint behaviors, with the other being webHttp.  As it turns out, enableWebScript is a subclass of webHttp that provides the AJAX functionality, such as client proxy generation, which we will see later.
  3. serviceHostingEnvironment: The default configuration for WCF services running with ASP.NET is for them to run side-by-side.  In this configuration, the ASP.NET runtime does not participate in the processing of WCF requests.  Things like the ASP.NET context and session are not available to the service.  If aspNetCompatibilityEnabled is set to true, as it is here, the WCF requests participate in the ASP.NET request pipeline.

* What is most important to gleen from this configuration is that 2 things are required to take advantage of REST in WCF: 1) Set the binding to webHttpBinding and 2) choose either a webHttp or enableWebScript endpoint behavior.

CatalogService.cs 

[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode =
    AspNetCompatibilityRequirementsMode.Allowed)]
public class CatalogService
{
    // Add [WebGet] attribute to use HTTP GET 
    [OperationContract]
    public void DoWork()
    {
        // Add your operation implementation here 
        return;
    }

    // Add more operations here and mark them with [OperationContract] 
}

This is where we have to actually do some work.  If you read the section above, you will note that we are using the interface inference method of defining a service contract.  You will note that the ServiceContract attribute is decorating a class and not an interface.  I believe this is done in an attempt to simplify the implementation.  It eliminates the interface type altogether.  Not sure if I agree… actually, I am sure that I disagree with this approach, but not vehemently.

At any rate, at this point, we need to build our implementation.  The first thing we need to do is to set the Namespace parameter of the ServiceContract attribute.  This turns out to be quite important.  The namespace for the proxy class that allows us to call our service is taken from our service namespace set here.  I am going to set the namespace to urn:shopping/services.

[ServiceContract(Namespace = "urn:shopping/services")]

Next, I am going to add one operation (a method decorated with an OperationContract attribute).  My operation will use LINQ to SQL to fetch a page of products from the database.  This implementation returns a ProductGroupingData type that contains a ProductData type.  I chose this approach because I wanted to return not only the product data (ProductData), but also some metadata that will be helpful for paging (StartIndex, PageSize and TotalCount in ProductGrouping Data.  Here are those types:

[DataContract]
public class ProductData
{
    [DataMember]
    public int ProductId;

    [DataMember]
    public string ProductName;

    [DataMember]
    public string Description;

    [DataMember]
    public decimal Price;

    [DataMember]
    public string ProductImage;
}

[DataContract]
public class ProductGroupingData
{
    [DataMember]
    public List<ProductData> Products;

    [DataMember]
    public int StartIndex;

    [DataMember]
    public int PageSize;

    [DataMember]
    public int TotalCount = 0;
}

Here is the implementation:

[OperationContract]
public ProductGroupingData GetProductGrouping(int startIndex, int pageSize)
{
    using (CatalogDataContext catalogCtx = new CatalogDataContext())
    {
        // Set up the query 
        var products = from p in catalogCtx.Products
                       orderby p.ProductName
                       select new ProductData()
                       {
                           ProductId = p.ProductId,
                           ProductName = p.ProductName,
                           Description = p.ProductDescription,
                           Price = p.Price,
                           ProductImage = p.ProductImage
                       };

        // Use skip and take extension methods for server side paging 
        //  and call ToList to execute the query 
        var productColl = products.Skip(startIndex).Take(pageSize).ToList();

        // Add the metadata 
        var package = new ProductGroupingData()
        {
            Products = productColl,
            StartIndex = startIndex,
            PageSize = pageSize,
            TotalCount = catalogCtx.Products.Count()
        };

        return package;
    }
}

At this point, we are done building our AJAX-enabled service.  What we mean by AJAX-enabled is that the service can be easily called by an AJAX client.  We will tackle that code in Part III tomorrow.

Until tomorrow…

Comments

One Response to “REST in WCF – Part II (AJAX Friendly Services, Creating The Service)”
  1. Simeon Potts says:

    “Behavior Configuration: For the webHttpBinding, you need to set this attribute to an endpoint behavior that has a child node of webHttp or enableWebScript.” Thank you for this, I think I’m going to make this into a poster on my wall.

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