AJAX-enabled Services

Inside JavaScript Proxy Classes for AJAX Services





AJAX-enabled Services

Inside JavaScript Proxy Classes for AJAX Services


By Dino Esposito


I briefly touched on AJAX-enabled services in Remote Web Operations the AJAX Way while discovering the most effective techniques to ping a remote server for fresh information. So just what are AJAX-enabled services? Quite simply, they are ASP.NET Web services or Windows Communication Foundation (WCF) services slightly modified to fit into the ASP.NET AJAX runtime environment. Put another way, AJAX-enabled services are Web or WCF services that can be successfully and safely invoked directly from a client browser using JavaScript code or, when available, from a Silverlight 2.0 WPF application.


ASP.NET Web services can be used with ASP.NET 3.5, as well as with ASP.NET 2.0 when ASP.NET AJAX Extensions 1.0 is installed. WCF services, instead, are only supported in ASP.NET 3.5. Whatever flavor of service you decide to use, a JavaScript proxy class is used to mirror the remote API within the browser. The JavaScript proxy class saves you from the burden of setting up the HTTP request to the service endpoint and managing the response. This helper class is automatically generated by the ASP.NET runtime when you properly reference a service.


In this article, I ll first write a sample service (both Web service and WCF service), then discuss the internal structure of the JavaScript proxy class.


Defining a Sample Web Service

You don t strictly need to specify a contract to write an ASP.NET Web service. However, doing so is not a bad habit, and puts you in the right mood for using WCF services where, instead, an explicit contract is strictly required. A contract for a Web service is a plain interface:


namespace Samples.Services


   public interface ICustomerService


       Customer LookupCustomer(string id);




You are responsible for the definition of the Customer class and any other non-primitive data types you use. In an ASP.NET 3.5 project, you can add a LINQ to SQL class and have the O/R designer of Visual Studio 2008 generate the Customer class for you. This is just what I did in the sample project: I added a reference to the Northwind database and added the Customers table to the layout. The resulting Customer class is a class that mirrors the structure of records in the Customers table.


The implementation of an AJAX-enabled Web service is nearly identical to the implementation of a classic ASP.NET Web service, except for the ScriptService attribute, as shown in Figure 1.


namespace Samples.Services



   public class CustomerService : ICustomerService


       public CustomerService()




       public Customer LookupCustomer(string id)






Figure 1: Implementation of an AJAX-enabled Web service.


ScriptService is the key attribute that enables AJAX support for an ASP.NET Web service. Only Web services decorated with the ScriptService attribute can be invoked via script from a client browser. To consume the Web service, you need an ASMX endpoint:


<%@ WebService Language="C#" CodeBehind=

 "~/App_Code/CustomerService.cs" Class=

 "Samples.Services.CustomerService" %>


The ASMX endpoint can be placed anywhere in the application and must be referenced by the ScriptManager control.


Defining a Sample WCF Service

To define a WCF service, start with a service contract and related data contracts for any non-primitive data type being used. Figure 2 shows contract and implementation of a WCF service that mimics the behavior of CustomerService.


namespace Samples.Services


  [ServiceContract(Namespace = "Samples.Services", Name =


 public interface ICustomerService



   Customer LookupCustomer(string id);


  [AspNetCompatibilityRequirements(RequirementsMode =


 public class CustomerService : ICustomerService


   public Customer LookupCustomer(string id)


     NorthwindDataContext context =

      new NorthwindDataContext();

     var data = (from c in context.Customers

                 where c.CustomerID == id

                 select c).SingleOrDefault();

     return (Customer) data;




Figure 2: The Customer WCF service.


As you can see, you must mark any WCF contract with the ServiceContract attribute and any operation in it must be decorated with the OperationContract attribute. In this case, it also is necessary that any non-primitive type (i.e., the Customer type) be decorated with the DataContract attribute. The DataContract attribute enables the WCF runtime to generate a data transfer object that will be used in the serialization and deserialization of the data type.


If you use a LINQ to SQL data model with WCF services, you need auto-generated classes such as Customer to be marked as data contracts. You can manually edit the source code created by the O/R Visual Studio 2008 designer to add any missing attribute. However, in this way you ll lose the attribute with the first change to the LINQ to SQL model. Thankfully, the Visual Studio 2008 designer supports a visual property the SerializationMode property. If you set this property to Unidirectional, then a DataContract attribute will automatically be added to any context class for the current LINQ to SQL model (see Figure 3).


Figure 3: Setting the SerializationMode attribute of the LINQ to SQL data context.


A WCF service must be hosted by a runtime module and exposed through a set of bindings and addresses. Normally, this deployment information is written in the web.config file for WCF services to operate in ASP.NET applications. In ASP.NET 3.5, though, you find a made-to-measure factory class that automatically publishes the contract in the service. You activate the factory through a Factory attribute in the @ServiceHost directive:


<%@ ServiceHost Factory="System.ServiceModel.Activation.



 CustomerService.cs" %>


It should be noted that when the Web factory class is used, the service class must implement exactly one contract. A service class that implements multiple contracts needs to use a regular ServiceHost and publish service information via registration.


Generating the Proxy Class

In an ASP.NET AJAX page, the ScriptManager class maintains a list of service endpoints to be reached:






For each referenced service, the ScriptManager class inserts a


An ASP.NET request for a .asmx or .svc resource with a suffix of /js or /jsdebug instructs the ASP.NET runtime to return the proxy class. The name of the proxy class is based on different rules for Web and WCF services.


The Web service proxy class has the exact name of the Web service class, including namespace information. The proxy class, therefore, has the same name as the Class attribute in the @WebService directive of the .asmx resource. As mentioned, the proxy class exposes the same set of public methods as there are WebMethods on the source class. Here s how to invoke a Web service method from JavaScript:



 customerID, onCompleted);


The JavaScript proxy class for a WCF service has the same structure as a Web service proxy class, but the name is generated according to different rules. In particular, the name of the proxy class depends on the value of the Namespace and Name properties of the ServiceContract attribute. In no way does it depend on the fully qualified name of the WCF service class. Why is that?


Unlike a Web service class, a WCF service class may implement multiple contracts. Subsequently, it s the name of the contract, not the service class name, that is unique. A Web page connects to a particular service contract, rather than to a particular service class:


[ServiceContract(Namespace = "Samples.Services",

 Name = "CustomerService")]

public interface ICustomerService { ... }


For the preceding contract, the proxy class is named Samples.Services.CustomerService regardless of the namespace and class name used to implement the contract. The proxy class name comes from the concatenation of Namespace and Name attributes. The default namespace is Tempuri.org; the default class name is the name of the contract interface (ICustomerService, in the previous example). If the namespace is a variation of a URI (i.e., it looks like http://aspnetPRO/corecoder), special characters such as slashes and punctuation marks will be removed.


Structure of the Proxy Class

Figure 4 shows the core structure of the JavaScript proxy class for a Web or WCF service. The proxy is a JavaScript class based on the Microsoft AJAX library where the prototype lists all service methods. The last statement in Figure 4 creates a global instance of the proxy class.



Samples.Services.CustomerService = function()



 this._timeout = 0;

 this._userContext = null;

 this._succeeded = null;

 this._failed = null;


Samples.Services.CustomerService.prototype =


  LookupCustomer : function(customerID, succeededCallback,

    failedCallback, userContext)


    return this._invoke(Samples.Services.CustomerService.get_path(),

      'LookupCustomer', false, {customerID}, succeededCallback,

     failedCallback, userContext);






Figure 4: The JavaScript proxy class for the Customer WCF service.


The methods you invoke from within your JavaScript to execute remote calls are defined around this global instance, as shown here:


Samples.Services.CustomerService.LookupCustomer =

 function(customerID, onSuccess,onFailed,userContext)



    LookupCustomer (customerID, onSuccess, onFailed,




The signature of each service method is enriched with a few additional arguments: success and failure callbacks, and a user context object. The definition of the proxy class is completed with a few public properties, as described in Figure 5. If you set a default succeeded callback, you don t have to specify a succeeded callback in any successive call as long as the desired callback function is the same. The same holds true for the failed callback and the user context object. The user context object is any JavaScript object, filled with any information that makes sense to you, that gets automatically passed to any callback that handles success or failure of the call.





Gets and sets the URL of the underlying Web service.


Gets and sets the duration (in seconds) before the method call times out.


Gets and sets the default JavaScript callback function to invoke for a successful call.


Gets and sets the default JavaScript callback function, if any, to invoke for a failed or timed-out call.


Gets and sets the default JavaScript object, if any, to be passed to success and failure callbacks.

Figure 5: Static properties on a JavaScript proxy class.


Executing a Call

Because the service call proceeds asynchronously, you need callbacks to catch up both in case of success and failure. The signature of the callbacks is similar, but the internal format of the results parameter can change quite a bit:


function method(results, context, methodName)


In case of a successful call, the results parameter indicates the JavaScript representation of the return value of the method. In case of a failed call, the results parameter carries error information. The context parameter is the same context object, if any, specified in the original call. Finally, methodName is a string that indicates the name of the called method.


The listing in Figure 6 shows JavaScript code to get a customer ID from a text box and invoke a service method. Next, a callback modifies the user interface with customer information.


function Button1_Click()


 var id = $get("txtCustomerName").value;




function onCompleted(results, context, methodName)


 var customer = results;

 $get("lblID").innerHTML = customer.CustomerID;

 $get("lblCompany").innerHTML = customer.CompanyName;

 $get("lblCountry").innerHTML = customer.Country;

 $get("lblContact").innerHTML = customer.ContactName;


Figure 6: Get a customer ID from a text box and invoke a service method.


More on Error Handling

The on-failed callback is used after a server exception during the execution of the service method. In this case, the HTTP response reports an internal error (HTTP 500 code) and its body contains the JSON-serialized version of a JavaScript Error object. Here s an example:


{"Message":"Customer not found", "StackTrace":"

 at Samples.Services.CustomerService.LookupCustomer() in




You can use Message and StackTrace properties to arrange your own error handling. The Message property reports the server exception message. You can use a different error handler callback for each remote call, or you can designate a default function to be invoked if one is not otherwise specified. A remote call that takes a while to complete is not necessarily a good thing for the application. To mitigate the impact of lengthy AJAX methods on the application scalability, you can set a timeout:




The timeout attribute is global and applies to all methods of the proxy class. This means that if you want to timeout only one method call, you need to reset the timeout after the method s call. To reset the timeout, simply set the timeout property to zero.



To definitely move away from postbacks, you need the ability to execute server calls from the client. JavaScript and the underlying XMLHttpRequest object provide this ability. However, you need a standard and reliable way of defining the server API: contract-based services are the right way to go. In ASP.NET AJAX, you can define the server API using AJAX-enabled versions of ASP.NET Web services or WCF services. In both cases, the system transparently generates a JavaScript proxy class to let you make client calls quite comfortably.


Files accompanying this article are available for download.


Dino Esposito specializes mainly in ASP.NET, AJAX, and RIA solutions, and is the author of the upcoming Programming ASP.NET 3.5 Core Reference (Microsoft Press, 2008). He also wrote Introducing ASP.NET AJAX, always for Microsoft Press. Late-breaking news is available at http://weblogs.asp.net/despos.




Hide comments


  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.