An Extensive Examination of Web Services: Part 3By Scott Mitchell
|An Extensive Examination of Web Services Index|
An Extensive Examination of Web Services is a multi-part article series spanning
several months. Listed below are the current "parts," along with a very brief synopsis and the
Welcome to Part 3 of An Extensive Examination of Web Services! In this part we'll examine how to consume a Web service from a client application. The client application, mind you, can be any application that can issue an HTTP request to the Web service. That is, the client can be what we typically think of as a client - say a stand-alone Windows desktop application - or it can be what we more traditionally think of as a server - such as an ASP.NET Web page on a Web server.
Recall from our discussions in Part 2 that Web services communicate via messages formatted in the SOAP standard, where the messages are transmitted over the Internet using (typically) the HTTP protocol. A Web service call begins with the client sending a request for a particular method to the Web service. The Web service then processes this request and returns the result of the method wrapped up in a SOAP message. (See this diagram for a graphical illustration of a Web service interaction.) Also, in Part 2 we briefly discussed what WSDL was. Namely, is it the means by which a Web service is formally defined. It is the WSDL document that specifically spells out how the messages that will be passed to and from the Web service must be serialized. That is, how the method to be called is specified, and how the input and output parameters are represented in XML.
In order to call a Web service from a client application, the client needs to do a couple of things:
- It must be able to inspect the Web service's WSDL document so that it knows how to serialize the call to the Web service.
- It must serialize the input messages, and wrap everything up into a SOAP message.
- It must make an HTTP request to the URL the Web service resides at. It then must wait for an HTTP response.
- Upon receiving the response, the client must deserialize the return values.
Clearly the steps required here are a tall order. Fortunately, much of the complexity of this process is abstracted away through the use of a proxy class. As we'll discuss in this article, the .NET Framework SDK ships with a tool that, given a WSDL document, will automatically generate an appropriate proxy class. Before we examine how to use this tool, we'll first discuss WSDL in more detail.
WSDL, or Web Service Description Language, is an XML-formatted document that formally defines the Web service. Specifically, the WSDL document spells out in precise terms:
- The data types of the messages a Web service will accept and send (these message types are spelled out using XML Schema)
- What message formats are accepted (SOAP, HTTP-POST, HTTP-GET, etc.)
- For SOAP messages, the style and encoding of the SOAP message, and
- The Web service's endpoint (the URL the Web service resides at)
You can view the WSDL document for a .NET Web service by visiting the .NET Web service endpoint through a browser. Doing so will display information about the Web service (shown below), which includes a hyperlink titled "Service Description."
Clicking the "Service Description" link will display the Web service's WSDL document. In Part 2
of this article series we created a very simple Web service with two methods:
both of which took two integers as input and returns the sum or difference, respectively. Let's examine this Web service's
WSDL document. (You can view the WSDL document in its entirety if you'd like...)
<definitions>element, which is the document's root element. This element does nothing more that serve as the root element and specify the namespaces used in the WSDL document. The first child element is
<types>, which spells out the message data types used in the Web service via the XML Schema specification. Recall that there are two messages associated with each method defined in the Web service - the request message and the response message. The following snippet defines the request and response messages for the
XML Schema is used to define the structure of an XML document. Therefore, the
<types> element here
defines the serialized XML for the request and response messages to the
The first data type specifies is an XML document that contains an
<Add> element with
two children elements:
<y>, whose text data is of type integer.
Furthermore, there should be one, and exactly one, of each of these two children elements. That is, the following
XML document conforms to the schema:
Similarly, another data type defined is one that contains an XML element named
<AddResponse> and that
has precisely one child element,
<AddResult>, whose text data is of type integer.
In addition to these two data types, the WSDL document contains two additional data types not shown in the above
|For More Information on XML Schema...|
|XML Schema is an XML-formatted specification for indicating the schema of an XML document. A thorough discussion of XML Schema is far beyond the scope of this article. For more information, check out the XML Schema Tutorial or O'Reilly's book XML Schema.|
<types>element is the
<message>element maps the messages the Web service provides with the data types defined in the
<types>element. For example, the
Add()method's two messages - named for us as
AddSoapOut- are assigned the appropriate data types with the following
The next element in a WSDL document is the
<portType> element, which specifies what methods
the Web service provides, and the input and output messages for these methods. For our simple Web service there
are two methods:
Subtract(). The following shows the
for our Web service:
<portType>element comes the
<binding>element, which specifies the message protocols accepted by the Web service. Typically there will only be one
<binding>element, which specifies that the SOAP protocol is used. However, there are other Web service protocols such as HTTP-POST and HTTP-GET. Not only does the
<binding>element specify what protocols are supported, but also the details about these protocols. For example, the SOAP protocol supports different styles and encodings of the actual SOAP message - these details need to be spelled out here.
A thorough discussion of SOAP message styles and encodings is a bit beyond the scope of this article. Realize that in the early days of Web services there were ongoing discussions as to the best way to specify the method of the Web service to call, and how the types of the messages were defined. There are two types of styles allowed, either RPC or Document. Similarly, there are two encoding types: literal, and encoded. Realize today, and moving forward into the future, the preferred style and encoding is Document/Literal, which is the style and encoding used by default when creating Web services with Visual Studio .NET. The only time you might need to use alternative styles or encodings is if you are building a Web service that needs to interact with a legacy client. (A more thorough discussion of the style and encoding differences can be found at this FAQ.)
The final element is a WSDL document is the
<service> element, which specifies the Web service's
endpoint for each binding.
Consuming a Web Service
In order for a client to be able to consume a Web service, the client must know a bit about the Web service - namely, it must know where the Web service "lives" and how to invoke its methods (by knowing how to serialize and deserialize the messages it passes to and receives from the Web service). This information is contained wholly in the Web service's WSDL document (which is why we spent so much time discussing the WSDL document in the first place!). In addition to knowing how to invoke the Web service's methods, the client must also go through the motions involved in creating the SOAP message to send to the Web service, making the actual HTTP request, and then deserializing the HTTP response. These steps, mind you, will need to be repeated for each Web service a client wishes to consume.
Whenever you are faced with too much complexity, you should always think, "encapsulation." That is, it is likely worthwhile to build a class that provides an easy to understand interface by encapsulating all of the complexity. For example, for calling a Web service it would be nice to have a class with the same methods as the Web service itself. From our client, then, we could just call this class's methods and the class will worry about the hard work - serializing the input parameters into a SOAP message, making the HTTP request, and deserializing the response.
Fortunately, we do not have to create this class ourselves, as Microsoft provides a tool in the .NET Framework SDK that will do just this. To use this tool we just need to specify the WSDL document of the Web service - the tool will then retrieve the WSDL document and build a class that can then be used to invoke the Web service. (This class is called a proxy class because it implements the Proxy Pattern.)
This will create a class with the same name as the Web service, with methods identical to that of the Web service.
The class is placed within the namespace specified by the value in the Web Reference Name textbox in the Add Web Reference
dialog box. For our sample Web service, the namespace used was
localhost. The name of the Web service
Service1, so the proxy class's name is
Service1. The proxy class has a number of methods,
but the two that we care about are:
Add(int, int), and
These two methods are, not coincidentally, the two methods provided by the Web service. We can now have our client
application consume the Web service by accessing the local methods of our proxy class. When our client application
calls the proxy class's
Add() method, the proxy class serializes the input parameters into a SOAP message,
makes the HTTP request to the Web service's endpoint, receives the response, deserializes it, and returns the resulting
value to the client application. This interaction is outlined in the following diagram:
The following code shows how to consume the Web service. Again, it's as simple as creating an instance of the
proxy class and calling the corresponding method. The following code shows some VB.NET code that displaying the results
of a call to the
|Creating a Proxy Class Without VS.NET|
If you don't have Visual Studio .NET, but do have the .NET Framework SDK installed, you can still create a proxy class
to consume a Web service. The downside, though, is that you have to do so through a command-line interface. The tool
is called |
In this article we examined how a client can consume a Web service through the use of a proxy class. A proxy class is a class that encapsulates the complexity of calling a Web service and exposes this complexity through a simplified interface. From the client application's perspective, the Web service is simply a local component - the client doesn't have to worry about the specifics of how to serialize a SOAP message, or how to make an HTTP request.
In order to create the proxy class, it is important that you have access to the Web service's WSDL document. The WSDL document is an XML-formatted document that formally defines a Web service. It specifies the data types of the messages, what protocols are accepted, and the Web service's endpoint. Given nothing more than a Web service's WSDL, you'll find that with Visual Studio .NET the number of minutes needed to go from no code to actually calling the Web service can be counted on one hand.