When you think ASP, think...
Recent Articles
All Articles
ASP.NET Articles
ASPFAQs.com
Message Board
Related Web Technologies
User Tips!
Coding Tips
Search

Sections:
Book Reviews
Sample Chapters
Commonly Asked Message Board Questions
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Security
Stump the SQL Guru!
Web Hosts
XML
Information:
Advertise
Feedback
Author an Article

ASP ASP.NET ASP FAQs Message Board Feedback
 
Print this Page!
Published: Wednesday, February 24, 2010

Comparing the Performance of Visual Studio's Web Reference to a Custom Class

By Sam Menard, John Jakovich, and Jamie Davis


Introduction


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!

- continued -

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.

// Get data for 2009...
WebReferenceProxy proxy = new WebReferenceProxy();
DataSet performances = proxy.GetData("1/1/2009", "12/31/2009");

After the 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 SoapCall class.

//Prepare objects and create Web Service parameters
ASCIIEncoding encoding = new ASCIIEncoding();
StringBuilder parameters = new StringBuilder();
parameters.Append("sStartDate=1/1/2008&");
parameters.Append("sEndDate=1/1/2009&");

byte[] payload = encoding.GetBytes(parameters.ToString());
string Url = @"http://WebServiceUrl/GetPerformances";
//Call the Web Service
System.Net.HttpWebRequest wr = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(Url);
wr.Method = "POST";
wr.KeepAlive = false;
wr.ContentType = "application/x-www-form-urlencoded";
wr.ContentLength = payload.Length;

//Retrieve the response
System.Net.HttpWebResponse webResponse;
System.IO.Stream wrStream = wr.GetRequestStream();
wrStream.Write(payload, 0, payload.Length);
wrStream.Close();
webResponse = (System.Net.HttpWebResponse)wr.GetResponse();

//Put the response stream in an XML document
Stream baseStream = webResponse.GetResponseStream();
System.IO.StreamReader sr = new System.IO.StreamReader(baseStream);
System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
xmlDoc.LoadXml(sr.ReadToEnd());

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 HttpWebRequest object's 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 SoapCall class 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 SoapCall method.

The time (in milliseconds) needed to retrieve and load the data.

One reason for the performance discrepancy is the use of the XmlDocument object in the SoapCall class. .NET's XPathDocument class 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 SoapCall class.

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.Write statements to emit the data and HTML markup of interest. For the XmlDocument approach, 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.

The time (in milliseconds) needed to sort and iterate the data returned by the web service.

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 Response.Write statements is faster than using XSLT to transform XML into HTML.

Happy Programming!

  • By Sam Menard, John Jakovich, and Jamie Davis


    Further Readings:


  • An Extensive Examination of Web Services


  • ASP.NET [1.x] [2.0] | ASPMessageboard.com | ASPFAQs.com | Advertise | Feedback | Author an Article