Sunday, December 5, 2010

WCF Services Assisting ASP.NET Ajax

We love the Telerik ASP.NET Ajax Control set and often rely on it for our Ajax communication in ASP.NET. But sometimes the need for efficiency out weights the ease and maintenance of the plug and play solutions.

We needed a way to eliminate the page request that happens when interacting with one of our ajaxified controls. UpdatePanels and Telerik's AjaxManager still require the page to go through its entire lifecycle so that a portion of the page can be sent back to the browser. We ventured down a few paths that would allow us to use a usercontrol without loading the hosting page, but those solutions were a hack job at best.

It turns out that using WCF Services within ASP.NET is quite an elegant solution when having to roll your own AJAX solution. With the proper configuration, the services can run along the ASP.NET pipeline giving you access to authentication and authorization events and the user's session. The services can even handle writing your response to JSON.

Add a WCF Service to your ASP.NET Web Application. Then double check your web.config to make sure that it has the enableWebScript attribute declared and the aspNetCompatibilityEnabled is set to true. The enableWebScript and aspNetCompatibilityEnabled attributes make the WCF service able to participate in the ASP.NET pipeline.

<system.serviceModel>
  <behaviors>
    <endpointBehaviors>
      <behavior name="WcfServices.EndpointBehavior">
        <enableWebScript /> <!-- required for ASP.NET pipeline integration -->
      </behavior>
    </endpointBehaviors>
    <serviceBehaviors>
      <behavior name="WcfServices.ServiceBehavior">
        <serviceMetadata httpGetEnabled="true" /> <!-- required for RESTful services -->
      </behavior>
    </serviceBehaviors>
  </behaviors>
  <serviceHostingEnvironment aspNetCompatibilityEnabled="true"
    multipleSiteBindingsEnabled="true" />
  <services>
    <service name="Demo.WcfServices.NewsFeedService" behaviorConfiguration="WcfServices.ServiceBehavior">
      <endpoint behaviorConfiguration="WcfServices.EndpointBehavior"
        binding="webHttpBinding" contract="Demo.WcfServices.ServiceContracts.INewsFeedService" />
    </service>
  </services>
</system.serviceModel>

You can consume your WCF services by adding a ServiceReference on a page.

<asp:ScriptManagerProxy runat="server">
    <Services>
        <asp:ServiceReference Path="~/WcfServices/NewsFeedService.svc" />
    </Services>
</asp:ScriptManagerProxy>

By adding the ServiceReference, the page will add a javascript include to a proxy class that contains the service prototypes. It contains the prototypes that you will use when calling the service from javascript. To see the javascript proxy class, navigate to the SVC file URL and add either "/JS" or "/JSDEBUG" to the URL. Examine the output for the javascript function prototypes.

As you can see below, the javascript WCF call looks clean and is easy to follow. This approach has many advantages and it decouples us from the tedious page lifecycle that is induced through UpdatePanels and Telerik's Ajax framework.

function getLatestNews(lastNewsId) {
    Demo.INewsFeedService.GetLatestNews(lastNewsId, callbackSuccess, callbackFailed);
}
function callbackSuccess(result) {
    $("#newsFeed").prependTo(result);
}

In our case we used AJAX to WCF in order to get an updated XHTML fragment. Instead of using a usercontrol for presenting the dataset, we used XSLT to render the XHTML for the control. This makes it easy for the WCF AJAX call to return XHTML fragments that can be replaced on the page at the AJAX callback. So go ahead and trade in your UpdatePanels for WCF Services next time you have the need for a specialized AJAX call.

Links