Web Service Optimization

Web Service Optimization

As a software application that makes itself available only via Internet connections, a Web service is at risk of being, or becoming, a slow application. For this reason, optimization is more than ever a critical factor. The overall performance is affected by the network latency as well as the format of the protocol being used. The pair of HTTP and SOAP is based on text, and SOAP in particular is quite a verbose protocol. This results in packets significantly larger than those typical of binary protocols such as CORBA or even DCOM. However, relying on HTTP and SOAP is at the foundation of the Web service concept, because they are critical for interoperability and loosely coupled connections between clients and servers.

To improve the usability of a Web service (the characteristic you should focus optimization efforts on), you should look elsewhere and involve the client applications as well. In particular, asynchronous calls and custom SOAP extensions can help considerably.

Asynchronous Calls

A call to a Web service method can occur both synchronously and asynchronously, depending on how the client sets it up. When you use proxy classes, the method invocation typically takes place in a synchronous way. Fortunately, you do not have to change the Web service’s structure to make it support asynchronous calls.

Asynchronous calls make sense in Windows Forms applications where the user has a lot of controls to work with while waiting for the response to arrive. Web pages, which are created on the server without user intervention, have nothing to gain from asynchronous calls. The only exception to this is when you have HTML pages that use Dynamic HTML behaviors to call into Web services.

The proxy class for the Web service already contains all that you need to set up an asynchronous call. The Northwind Info Service we built in this chapter has three Web methods that correspond to the overloads of the same Get­Employees method. In addition to the GetEmployees method, the proxy class also features method triplets such as GetEmployees, BeginGetEmployees, and EndGetEmployees. In particular, you find the following:

  • GetEmployees, BeginGetEmployees, EndGetEmployees

  • GetEmployees, BeginGetEmployees1, EndGetEmployees1

  • GetEmployees, BeginGetEmployees2, EndGetEmployees2

The first method of the triplet is one of the overloads for the Web service GetEmployees method. That method calls its Web service counterpart in a synchronous way. The other two methods, instead, call into the same Web service method but in an asynchronous fashion. The following code snippet shows an excerpt from the proxy class code that illustrates how the synchronous call works:

public System.Data.DataSet GetEmployees() {
    object[] results = this.Invoke("GetEmployees", new object[0]);
    return ((System.Data.DataSet)(results[0]));

The overload considered in this code is GetEmployees(), so it takes no arguments and returns all the employees in the database.

Issuing Asynchronous Calls

An asynchronous call is made of two distinct function calls. The first function call opens the connection and begins the data download. The second function call informs the Web service requestor that the download is complete and gives the requestor a chance to grab the resultant object. The asynchronous methods for GetEmployees() have the following components:

IAsyncResult BeginGetEmployees(AsyncCallback callback, object asyncState) 
    return this.BeginInvoke("GetEmployees", 
        new object[0], callback, asyncState);

DataSet EndGetEmployees(System.IAsyncResult asyncResult) 
    object[] results = this.EndInvoke(asyncResult);
    return ((System.Data.DataSet)(results[0]));

BeginGetEmployees takes all its regular arguments plus two more: an asynchronous callback function and a reference to a proxy class object. It returns an object of type IAsyncResult, which provides a way to monitor what’s going on over the network. By using an object of IAsyncResult, a software client can check at any time whether the download is complete. The end of the execution can be notified automatically via a callback function, that is, an object of type AsyncCallback.

Let’s suppose that you want to make the following call asynchronous:

NorthwindInfoService nwis = new NorthwindInfoService(); 
DataSet ds = nwis.GetEmployees(1, 9);

You first get the distinct name for the overloads, which has been set in the proxy class. You do this snooping in the source code of the proxy. If no overloaded method is involved, you can determine the names of asynchronous methods pretty easily: they are BeginMethodName and EndMethodName. As for the Northwind Info Service, the asynchronous pair for the GetEmployees(first, last) method is BeginGetEmployees1 and EndGetEmployees1. You begin the download with the following code:

AsyncCallback ac = new AsyncCallback(NWServiceCallback);
NorthwindInfoService nwis = new NorthwindInfoService(); 
nwis.BeginGetEmployees1(1, 9, ac, nwis);

NWServiceCallback is the name of a method defined in a class within the client application. This method is automatically called back by the proxy class when the download is complete. The typical implementation of the method is shown here:

void NWServiceCallback(IAsyncResult iar) 
    NorthwindInfoService nwis = (NorthwindInfoService) iar.AsyncState;
    m_DataSet = nwis.EndGetEmployees1(iar);

The AsyncState property of the IAsyncResult argument evaluates to the instance of the proxy class in use. Once you hold a living instance of the proxy class, you call the method that terminates the connection with the Web service. This method receives the underlying IAsyncResult object and finally returns the expected data. Figure 9-9 shows two screens for a sample Windows Forms application that downloads a DataSet object from Northwind Info Service.

Figure 9-9
The sample application downloads data asynchronously from a Web service.
SOAP Extensions

A SOAP extension is like a hook that you register with the Web service to access the raw SOAP XML either as it is about to be transmitted or as it’s received. A SOAP extension works both on the client by using proxy classes and on the server. When you want to play tricks or customize the underlying XML, SOAP extensions provide the right connection point. A valid example of their use is to encrypt or compress method parameters for improved performance and security.

The ASP.NET SOAP extension architecture closely resembles the hook architecture in Win32. Basically, a registered SOAP extension can inspect or modify a SOAP message at specific stages in message processing on either the client or the server. A SOAP extension is made of two elements: the extension class and the attribute class.

You write an ASP.NET SOAP extension by creating two classes. The extension class inherits from the SoapExtension class, whereas the attribute class inherits from SoapExtensionAttribute. After you have created, say, a MySoap­Extension class, you associate it with a Web service method as follows:

[MySoapExtension()]public object DoSomething() 


All SOAP packets originated by calls to that Web service method are then filtered by the extension. The critical method of a SOAP extension is ProcessMessage:

public abstract void ProcessMessage(SoapMessage message);

The argument passed to this method is SoapClientMessage when the extension is invoked on the client, and SoapServerMessage when the extension works on the server. ProcessMessage implements a switch statement and does different tasks according to the stage of the message. There are four possible stages: BeforeSerialize, AfterSerialize, BeforeDeserialize, and AfterDeserialize.

A SOAP extension attribute is a worker class that provides custom properties specific to the SOAP extension. Derived attribute classes must necessarily override the ExtensionType property, which returns the type of extension that is associated with the attribute. Here is an example:

public class MySoapExtensionAttribute : SoapExtensionAttribute 
    // Define custom attributes here...

    public override Type ExtensionType 
        get { return typeof(MySoapExtension); }

The point of contact between the SOAP attribute class and the extension class is the GetInitializer method on the SOAP extension class:

public abstract object GetInitializer(
    LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute);

Any SOAP extension–specific data gets passed using the custom attribute class and can be cached in the SOAP extension class at this point. GetInitializer is called only once in the extension’s lifetime. The use of attribute classes decouples the logic of the SOAP extension from any custom attribute it might need.

Extreme Optimization

Round-trips are one of the most critical aspects of Web services. When your Web service is destined to play in a corporate environment with all the bandwidth it can muster, a few extra round-trips won’t really degrade the performance too much—or at least this is our hope. Web services operate on the Web, however, so you do have to minimize round-trips.

I would suggest you consider making the Web service capable of executing an array of methods in batch mode—an extreme form of optimization. If you could figure out a way for clients to pack multiple calls together, and if you could make your Web service unpack and process all of them, you would be close to minimizing the impact of round-trips.

The overall idea of batch execution might sound attractive, but you’ll need to sort out a number of subtle and not so subtle issues. For example, what happens when you need to use the results of one call as the input of the next call? What if you need to control the flow through conditional expressions or loops? I don’t have the all-encompassing solution in my hands, but I do want to point you to a feature that very few software applications can boast about having. I’m talking about the ability to use C# and any other .NET language as a script.

The .NET Framework provides classes in the System.CodeDom.Compiler namespace that let you compile C# code on the fly and in memory, which means you never write the resultant assembly to disk. The Web service can expose a method that accepts a C# string and then just compile, run, and return the results to the client.

What would this kind of scripted Web service actually look like? I think the C# code you send in would closely resemble a kind of Web stored procedure, with the Web service working like a database. In terms of performance, this approach makes sense because you maximize the information transfer both for data coming and data going. In terms of its feasibility, consider what will happen with the next version of Microsoft SQL Server. Although the product is an unmanaged application, it will certainly host the .NET CLR. This simple fact would enable it to execute C# and Visual Basic .NET code within the environment. So chances are good that in the near future, you will be able to write compiled stored procedures using C#. SQL Server will add its own object model (say, a variation of today’s SQL Distributed Management Objects (SQL-DMO)) to let you code against tables and columns. You would be able to do the same with Web services as well with the public methods of the Web service to create the programmable object model.