Comparing the Performance of Visual Studio's Web Reference to a Custom ClassBy Sam Menard, John Jakovich, and Jamie Davis
As developers, we all make assumptions when programming. Perhaps the biggest assumption we make is that those libraries and tools that ship with the .NET Framework are the best way to accomplish a given task. For example, most developers assume that using ASP.NET's Membership system is the best way to manage user accounts in a website (rather than rolling your own user account store). Similarly, creating a Web Reference to communicate with a web service generates markup that auto-creates a proxy class, which handles the low-level details of invoking the web service, serializing parameters, and so on.
Recently a client made us question one of our fundamental assumptions about the .NET Framework and Web Services by asking, "Why should we use proxy class created by
Visual Studio to connect to a web service?" In this particular project we were calling a web service to retrieve data, which was then sorted, formatted slightly and displayed in
a web page. The client hypothesized that it would be more efficient to invoke the web service directly via the
HttpWebRequest class, retrieve the XML output, populate an
XmlDocument object, then use XSLT to output
the result to HTML. Surely that would be faster than using Visual Studio's auto-generated proxy class, right?
Prior to this request, we had never considered rolling our own proxy class; we had always taken advantage of the proxy classes Visual Studio auto-generated for us. Could these auto-generated proxy classes be inefficient? Would retrieving and parsing the web service's XML directly be more efficient? The only way to know for sure was to test my client's hypothesis.
This article details the experiment we set up to test this hypothesis. Read on to see our results!
Two Approaches for Calling a Web Service
Visual Studio's "Add Web Reference" option is a handy tool for calling a web service. This tool allows you to specify the URL to a web service's WSDL file, which is an XML-formatted file that describes the methods offered by the web service, it's communication protocols, and other low-level information essential to working with the web service. From this WSDL file, Visual Studio automatically generates a proxy class that "wraps" the web service methods. In a nutshell, the proxy class has a method for each of the web service's methods. You can call the proxy class's methods just like you would the methods of any other class in your project, but behind the scenes the proxy class serializes the method's input parameters into XML, makes an HTTP request to the web service, and deserializes the XML returned in the HTTP response. A full tutorial on web services is beyond the scope of this article; for more in-depth look at the fundamentals of web services see An Extensive Examination of Web Services.
While the proxy class greatly simplifies working with web services, there's no reason you have to use one to communicate with a web service. Alternatively, you could classes in
the .NET Framework's
System.Net namespace to make an HTTP request to the web service, and classes in the
System.Xml namespace to parse the response.
This was the approach put forth by our client - namely to call the web service using the
HttpWebRequest class and to use XSLT to convert the XML response into HTML,
which could then be emitted to the browser. This impetus behind this suggestion was the assumption that the auto-generated proxy class carries with it an overhead that
can be eliminated by a more direct method.
Test 1: Retrieving the Web Service's XML Data
In this project we call a web service to retrieve and display data from a business partner. Specifically, this web service is invoked by requesting a particular URL and by specifying date ranges through the POST header. The web service retrieves the data of interest and returns it as an ADO.NET DataSet serialized into XML.
Prior to our client's inquiry, we had accessed this web service using the proxy class auto-generated for us by Visual Studio. The proxy class contains a single method that
accepts two date values as inputs and returns a DataSet. The following code snippet shows how we would call the web service to get this data. Note that the proxy class
hides all of the implementation complexity of invoking the web service. We simply call the proxy class's method (
GetData, in this example) and the proxy class
handles all of the low-level work of serializing the two date values, making the HTTP request, and converting the resulting XML into an ADO.NET DataSet.
GetData method executes, the web service call has been completed and we have a DataSet object that contains the data retrieved from the web service.
At this point we can display the results in a grid, save the results to disk, sort the results, and so on.
However, our client assumed it would be more efficient to bypass the auto-generated proxy class and to instead make the web service call directly using the
HttpWebRequest class, putting the XML payload returned by the web service into an
XmlDocument object. To test this hypothesis we created a small,
lightweight class named
SoapCall that did just that. The following code snippet shows the pertinent lines of code in the
As you can clearly see, calling a web service directly involves a lot more code than when using a proxy class. That's one of the advantages of using a proxy class - it saves a tremendous amount of time by encapsulating all of the low-level code needed to package the input parameters, make the HTTP request, and parse the response.
The first highlighted line above shows the call to the
GetResponse method, which is what
actually sends the HTTP request and returns the HTTP response as a
Stream. The second highlighted line shows the response being
loaded into an
XmlDocument object. Once the web service's XML response has been loaded into an
XmlDocument we can do all sorts of interesting things
with it, including enumerating the data, filtering it (via XPath) and converting it into HTML for display (via XSLT).
Test 1: The Results
We ran the code that uses the auto-generated proxy class and the
SoapCallclass for 100 iterations, accessing an XML payload of 210 KB for each request. And the winner is... .NET's auto-generated proxy class. The test results demonstrate that using the auto-generated proxy class is about 50% faster than using the
One reason for the performance discrepancy is the use of the
XmlDocument object in the
SoapCall class. .NET's
offers a more efficient approach to parsing large XML documents, but using it requires a bit more code, especially when dealing with XML namespaces. Point being, it would be
possible to narrow the performance gap between these two approaches, but doing so would result in significantly more code in the
Test 2: HTML Generation
For this project, the data retrieved from the web service is sorted and then echoed to the user's browser with a small amount of formatting. When using the auto-generated proxy class, we sort the DataSet and then enumerate its rows, using
Response.Writestatements to emit the data and HTML markup of interest. For the
XmlDocumentapproach, our client suggested using XSLT to transform the sort the XML data and then transform it into HTML.
As you might expect, emitting the data using
Response.Write statements is faster than using XSLT to transform the XML into HTML. The graph below shows the
difference in execution time for each approach, both when sorting the data and when emitting it in the order with which it was returned by the web service.
Note that the absolute difference in time between both approaches is quite minimal (less than one millisecond). So under all but the most extreme circumstances of heavy load,
either approach is sufficient, although we prefer sorting the DataSet and emitting the markup via
Response.Write statements. Because of the simplicity of working
with a DataSet and blasting the markup to the client via
Response.Writes, such code is likely to be more readable and maintainable than using XSLT, which requires
a familiarity with XSLT and an additional syntax to master.
These test results show that using the Visual Studio's "Add Web Reference" to create an auto-generated proxy class is not only a time-saver, but is actually more efficient than
directly calling a web service from a custom class and loading its data into an
XmlDocument. Likewise, blasting markup directly to the browser via
statements is faster than using XSLT to transform XML into HTML.