Increasing web service client performance

As the demand for web enabled smart devices grows, more and more mobile applications will be using web services. Many of the folks who are already using web services with the .NET Compact Framework (NetCF) have come to me with performance issues. More often than not, the problem boils down to what happens when NetCF sees the first web method call on an instance of the service object.

When the first web method on a service object is called, NetCF uses Reflection to examine the service's proxy (to identify methods, headers, properties, etc). Unlike the full .NET Framework, NetCF (for working set size reasons) does not cache the results of this examination. Because of this, NetCF applications incur a performance penalty if they use multiple instances of the same service. The code below illustrates an application demonstrating this performance hit.

class SlowerWebServicePerformance
{
public static void Main()
{
// application setup

        foreach(String name in Friends)
{
String phoneNumber = CallWebService(name);

            // process / display the received data
}

        // application cleanup
}

    public static string CallWebService(String name)
{
// create new instance of the web service proxy object
PhoneBookService service = new PhoneBookService();

        // call the desired web method
// proxy reflection occurs here
return service.LookupPhoneNumber(name);
}
}

In the above example, each call to CallWebService creates a new instance of the fictitios PhoneBookService object with each call to the LookupPhoneNumber method causing NetCF to reflect over the service proxy code. In this example, users with a fewer friends are better off than those with more -- at least as far as application performance goes.

To minimize the effects of this issue, applications can create a class global instance of their web service object and make a simple call to it (check version, etc) during the startup code. The code below is a re-write of the previous example, this time using a class global service object.

class FasterWebServicePerformance
{
private static PhoneBookService service = new PhoneBookService();

    public static void Main()
{
// call a simple web service method to "prime the pump"
// proxy reflection occurs here
service.GetVersion();

        // application setup

        foreach(String name in Friends)
{
String phoneNumber = CallWebService(name);

            // process / display the received data
}

        // application cleanup
}

    public static string CallWebService(String name)
{
// call the desired web method
// proxy reflection does not occur
return service.LookupPhoneNumber(name);
}
}

As you can see from the second implementation, the Main method makes a call to the service's GetVersion method so that the reflection occurs exactly once during the course of the application. The data received from this call is not relevant here, since we merely wish to “prime the pump“. With this change, the penalty for having more friends is gone.

Please keep in mind, when writing your applications in this manner, any headers required by the web service are applied to all method calls, so do not modify them while a web method call is in progress (or your calls may fail based on bad header data). While this applies to asynchronous and multi-threaded applications, it's still a good idea to keep it in mind whenever working with web services. Since NetCF's web service client classes are thread safe, so you can feel free to pass your class global service instance to child threads -- provided that you remember the previous statement.

-- DK

[Edit: categorization]

Disclaimer:
This posting is provided "AS IS" with no warranties, and confers no rights.