"It would be possible to describe everything scientifically, but it would make no sense; it would be without meaning, as if you described a Beethoven symphony as a variation of wave pressure." -- Albert Einstein
Just as XML Schemas are used to describe the data types exposed by Web services, there is a need for a language that can be used to describe the complete interfaces exposed by Web services. In this chapter I explain the concepts and terminology behind the most commonly used language for describing Web service interfaces, the Web Services Description Language. I will show you how to write WSDL documents that describe your Web service’s interface and how to read WSDL documents for services that you want to invoke. The goal of this chapter is to teach you to create the SOAP request messages, and parse the SOAP response messages based on reading a WSDL. Tools, such as the SOAP Toolkit, can do this most of the time, but they sometimes fail especially if there are errors in the WSDL file. By knowing how to read and understand WSDL you can solve these problems yourself and go on to invoke the Web service or enable clients to invoke your Web service.
If I create a service called WeatherRetriever that exposes one method called GetTemperature like this:
Public GetTemperature(ByVal ZipCode As String) As Single
I want developers to invoke my Web service so I put together an HTML page that gives people the information they need to invoke it, which is:
· The name of the operation (the method) that it exposes, which is GetTemperature in this case. Clients would also need to know that the method takes in the zip code as an xsd:string and returns the current temperature as an xsd:float
· The protocol they can use to invoke this Web service. In this case, the service is accessible using SOAP over HTTP
· Whether the service is expecting RPC or document style SOAP messages
· Whether the service is expecting literal, SOAP encoded or other type of message
· The Web service’s location, for example http://www.learnXmlws.com/services/WeatherRetriever.asmx
Developers can read all this information and start writing clients that will invoke my Web services. But there are at least a couple of problems with providing this information in an informal way such as an HTML page.
First, the HTML page I come up with to publish this information is not a standard. So every Web service creator out there will have his or her own way of describing the service. As a developer, you would have to figure out how a particular Web service is described, read this description and try to understand it.
Second, using HTML or the back of a napkin to describe a Web service hardly provides a formal description that can be read and processed by your development tools. For example, if you make a mistake when reading my service description and you write a client that expects the temperature back as an xsd:int instead of an xsd:float, the error will manifest itself only at run time when your client actually invokes the Web service. Without a formal, machine-readable description of a Web service, there’s nothing your compiler can do to help you catch such errors at compile time.
Given a machine-readable Web service description, a development tool can be smart enough to check the names of operations you’re calling and the types of parameters you’re passing at compile time, which can save you hours of debugging later. A better development tool would even read the Web service description and generate the client code needed to invoke the Web service, thereby eliminating any manual work on your side. In fact, there are many tools that do exactly that, including wsdl.exe (part of the .NET platform) and Visual Studio .NET and a tool I wrote called VB6 Web Reference which I’ll discuss at the end of this chapter.
WSDL (Web Services Description Language) is an XML grammar for describing Web service interfaces, the protocols supported by the Web service, and the Web service location. Version 1.1 of the WSDL specification was authored by IBM Research and Microsoft and can be found at http://www.w3c.org/TR/wsdl. Although WSDL is not a W3C standard, nor is it a required part of building and invoking Web services, it is however, supported by many SOAP stacks and some tools, like wsdl.exe, use it to make it easy for clients to invoke Web services.
On the server side, when you expose a Web service with VB 6 and the SOAP Toolkit or with VB .NET, you automatically get a WSDL document describing your service. Other developers can read this WSDL document to learn your service’s interface and how to invoke it. On the client side, there are two ways to use a WSDL document. A development tool, like wsdl.exe, could read the WSDL document at design time and generate the client code necessary to invoke it as shown in Figure 4‑1. This is analogous to using a type library (the WSDL equivalent in the COM world) and early binding to invoke a COM component. Alternatively, a development tool could read the WSDL document at run time to generate the necessary requests and process the responses as shown in Figure 4‑2. This is analogous to using late binding to invoke a COM component. By default, .NET clients use early binding while clients using the SOAP Toolkit use late binding. This is just the default way of doing things using these two tools, but, with some extra work on your part, each tool can be used for both early and late binding.

Figure 4‑1
A development tool (e.g. wsdl.exe) can use a WSDL document at design time to generate client code that invokes the Web service

Figure 4‑2
A client-side SOAP stack can use a WSDL document at run time to formulate the Web service request message and understand the response message
Figure 4‑3 shows a client invoking a Web service using SOAP and another client invoking the same service using HTTP GET. Figure 4‑4 shows the same process with the various pieces labeled with WSDL terminology.

Figure 4‑3
Two clients invoking a Web service. Client A is using SOAP over HTTP while client B is using HTTP GET.

Figure 4‑4
WSDL terminology labeling the various parts of a client-service interaction.
In WSDL, a service exposes groups of operations (i.e. methods). Each group of operations is called a portType which is roughly analogous to an interface in the COM world. To invoke an operation, the client sends an input message and gets back an output message. The input message contains the data going to the service and the output message contains the data coming back from the service. Each item of data in a message is called a message part or simply part. The actual protocol used to invoke an operation and the actual format of the input and output messages are specified in a binding. The service itself is exposed to the world via one or more ports. Each port specifies two things: A network address where it’s located (e.g. http://www.learnXmlws.com/services/WeatherRetriever.asmx) and the binding to use with this port. A service may be exposed via multiple ports each with a different binding. For example, the service in Figure 4‑4 is exposed via two ports: One with a binding for SOAP and the other with a binding for HTTP GET.
Figure 4‑5 shows the components of a WSDL document and how they relate to each other. The boxes show the containment relations and the arrows show the reference relations.

Figure 4‑5
The components of a WSDL document and how they relate to one another.
A service contains one or more ports and each port references a binding. Each binding references a portType, the operations within that portType and the messages that make up each operation. Each portType contains zero or more operations. Each operation has an input and output message (I’ll discuss other message combinations later in this chapter). Each message has zero or more parts and each part is of some data type. The part’s type could be an XSD built-in type such as xsd:int or it could be a custom simple or complex type that’s defined using XSD.
Let’s take a look at a simple example Web service and the corresponding WSDL document. I created a VB 6 COM component called VB6Weather with one method:
Public Function GetTemperature(ByVal zipcode As String, _
ByVal celsius As Boolean) As Single
'code omitted
End Function
Then I ran the SOAP Toolkit’s WSDL Generator to create the corresponding WSDL which is shown in Listing 4‑1.
Listing 4‑1 A WSDL document created by the SOAP Toolkit’s WSDL Generator. (VBWSBook\Chapter4\ExampleWSDLs\VB6Weather.wsdl).
<?xml version='1.0' encoding='UTF-8' ?>
<!-- Generated 08/16/01 by Microsoft SOAP Toolkit WSDL File Generator, Version 1.02.813.0 -->
<definitions name ='VB6Weather'
targetNamespace = 'http://tempuri.org/wsdl/'
xmlns:wsdlns='http://tempuri.org/wsdl/'
xmlns:typens='http://tempuri.org/type'
xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/'
xmlns:xsd='http://www.w3.org/2001/XMLSchema'
xmlns:stk='http://schemas.microsoft.com/soap-toolkit/wsdl-extension'
xmlns='http://schemas.xmlsoap.org/wsdl/'>
<types>
<schema targetNamespace='http://tempuri.org/type'
xmlns='http://www.w3.org/2001/XMLSchema'
xmlns:SOAP-ENC='http://schemas.xmlsoap.org/soap/encoding/'
xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/'
elementFormDefault='qualified'>
</schema>
</types>
<message name='VB6Weather.GetTemperature'>
<part name='zipcode' type='xsd:string'/>
<part name='celsius' type='xsd:boolean'/>
</message>
<message name='VB6Weather.GetTemperatureResponse'>
<part name='Result' type='xsd:float'/>
</message>
<portType name='VB6WeatherSoapPort'>
<operation name='GetTemperature' parameterOrder='zipcode celsius'>
<input message='wsdlns:VB6Weather.GetTemperature' />
<output message='wsdlns:VB6Weather.GetTemperatureResponse' />
</operation>
</portType>
<binding name='VB6WeatherSoapBinding' type='wsdlns:VB6WeatherSoapPort' >
<stk:binding preferredEncoding='UTF-8'/>
<soap:binding
style='rpc'
transport='http://schemas.xmlsoap.org/soap/http' />
<operation name='GetTemperature' >
<soap:operation
soapAction='http://tempuri.org/action/VB6Weather.GetTemperature' />
<input>
<soap:body use='encoded' namespace='http://tempuri.org/message/'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' />
</input>
<output>
<soap:body use='encoded' namespace='http://tempuri.org/message/'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' />
</output>
</operation>
</binding>
<service name='VB6Weather' >
<port
name='VB6WeatherSoapPort'
binding='wsdlns:VB6WeatherSoapBinding' >
<soap:address location='http://localhost/webtest/vb6weather/VB6Weather.ASP' />
</port>
</service>
</definitions>
In chapter 3 you learned that there are four styles of SOAP messages which are RPC/encoded, RPC/literal, document/encoded, and document/literal. RPC/encoded is the default for exposing Web services using the Microsoft SOAP Toolkit, therefore the corresponding WSDL in Listing 4-1 is for RPC/encoded messages. In the next section, I’ll explain how the WSDL would differ for the other three styles of messages.
Looking at the document in Listing 4‑1, you see that the default namespace is declared as http://schemas.xmlsoap.org/wsdl/ which is the WSDL namespace. The document starts with the <definitions> element which is the document element (the topmost element) of a WSDL document and usually contains a few namespace declarations like you see here. The <definitions> element has an optional attribute called targetNamespace which defines the containing namespace for all WSDL items defined in this document such as messages, operations, and portTypes. The WSDL targetNamespace attribute is functionally similar to the XSD targetNamespace attribute discussed in Chapter 2.
The next element down is the <types> element which contains an XSD schema. This schema is where you’d define custom types to use with message parts such as TypeA and TypeB in Figure 4‑5. In this particular example there are no custom types because all the parameters and return value of the GetTemperature method can be represented using XSD built-in types.
Next comes the definition of messages using the <message> element. Each message has a unique name indicated by its name attribute. There are two messages: one represents the request and one represents the response. In this case, the SOAP Toolkit uses the names VB6Weather.GetTemperature and VB6Weather.GetTemperatureResponse following its Component.Method and Component.MethodResponse naming convention. Note that this is just the naming convention that the SOAP Toolkit follows, there is no standard way to name the messages, you can name them anything you like. The request message contains two parts correponding to the two parameters, zipcode and celsius, of the GetTemperature method. When using SOAP RPC, these part names must match the method parameter names because that’s a rule of SOAP RPC as discussed in chapter 3. Each part type is the XSD-equivalent of the VB parameter type. For example, A VB Boolean becomes an xsd:boolean and a VB Single becomes an xsd:float. Appendix A shows the SOAP Toolkit’s mapping between XSD types and VB types. The response message contains one part which corresponds to the method return value. If there were any ByRef parameters (i.e. in/out parameters), you would see the corresponding parts in both the request and response messages. If a Web service method has out parameters, they would be represented here as parts inside the response message. Although you cannot create methods with out parameters in Visual Basic, other languages such as C# allow you to do that, so you might encounter Web services that have out parameters.
The <portType> element defines the collection of methods exposed by the Web service so you can think of it as an interface implemented by the Web service. Each portType must have a unique name, which in this example is VB6WeatherSoapPort, but that name can be anything you like. Inside the <portType>, an <operation> element represents each method and contains a reference to the input (request) and output (response) messages using <input> and <output> element. An important thing to note here is that when referring to a message, you must use its fully qualified name. This is because a message belongs to the targetNamespace as defined in the <definitions> element. Looking back at the <definitions> element in Listing 4‑1, you’ll notice that the targetNamespace is defined as http://tempuri.org/wsdl/ and that the prefix wsdlns also maps to the same namespace. Therefore when you want to refer to the message called VB6Weather.GetTemperature, you have to prefix the message name with the targetNamespace prefix which is wsdlns in this example. This is exactly the same mechanism that XSD uses for specifying the targetNamespace of custom types then referring to those types later within your schema (see chapter 2). The <operation> element itself has the optional attribute parameterOrder which lists all method parameters in the order in which they appear in the method declaration. This attribute is optional, but you’ll usually see it in WSDL documents for Web services that use RPC-style SOAP (rather than document-style). At this point, you might be wondering how does a development tool (e.g. wsdl.exe) figure out whether each <part> is in, in/out, out, or the return value. The rules for determining this depend on the parameterOrder attribute as follows: for each parameter that appears in the parameterOrder list, if there’s a <part> with the same name in the input and output messages, then the parameter is in/out (ByRef). If there’s a <part> with the same name in the input message only, then the parameter is an in parameter (ByVal). If there’s a <part> with the same name in the output message only, then the parameter is an out parameter. Finally, if there’s a <part> in the output message that is not listed in the parameterOrder attribute that <part> is considered the method’s return value. Keep in mind that parameterOrder is optional, so if you encounter a WSDL document that does not specify parameterOrder don’t be surprised. In fact, most tools will not write a parameterOrder attribute when they generate a WSDL for a Web service that uses document style SOAP. This makes sense because with document style there are no parameters, just XML documents being exchanged within the SOAP envelope.
You might ask: Why is parameterOrder needed at all? Couldn’t we infer the order of parameters from the order of the <part> elements? I.e., the first <part> element is the first parameter and so on. This would actually work well if all Web services were created with languages that do not support out parameters. However, some languages, such as C#, support out parameters which could potentially lead to confusion in parameter orders. The problem is with methods that have a mix of in and out parameters. For example, here are two messages describing a method with in, in/out, and out parameters as well as a return value.
<message name="ExampleIn">
<part name="inParam" type="s:int" />
<part name="inoutParam" type="s:float" />
</message>
<message name="ExampleOut">
<part name="RetVal" type="s:string" />
<part name="outParam" type="s:string" />
<part name="inoutParam" type="s:float" />
</message>
Just by looking at these messages, you can tell that the inoutParam is the last parameter of the method because it comes last in both the input and output messages. But is inParam or outParam the first method parameter? You cannot make that determination without the paramterOrder attribute.
The next element is <binding> which also has a unique name and provides information on how to invoke operations of a particular portType using a particular protocol. In this example, the binding provides information on how to access the VB6WeatherSoapPort portType. The first element within the binding (<stk:binding>) is not part of WSDL at all. It is an element used by the SOAP Toolkit to indicate the preferred encoding to use when invoking operations. You can tell that <stk:binding> is not part of WSDL because its namespace is http://schemas.microsoft.com/soap-toolkit/wsdl-extension which is not the WSDL namespace. However WSDL does allow you to extend it using your own elements which are referred to as extensibility elements. You normally would not need to do this, but if you decide to extend a WSDL document by adding your own extensibility elements, keep in mind that the clients that read this WSDL may not understand what’s meant by those elements (unless of course you are also writing the clients). The next element is <soap:binding> which belongs to the namespace http://schemas.xmlsoap.org/wsdl/soap/ and provides information on whether to use RPC or document-style SOAP and what transport protocol to use with SOAP[1]. The <soap:binding> element is defined in the WSDL specification along with six other elements as part of the SOAP WSDL binding. Table 4‑1 lists all seven elements, where each element may appear in a WSDL document, and a brief description of each.
Table 4‑1
The SOAP WSDL extension elements.
|
Element |
Location |
Description |
|
<soap:address> |
As a child of a <port> element |
Provides the URL of the SOAP end point |
|
<soap:binding> |
As a child of a <binding> element |
Specifies whether to use document or RPC style soap and the transport protocol to use |
|
<soap:body> |
As a child of an <input> or <output> element that’s a child of a <binding> element |
Specifies the namespace of the SOAP <Body> contents and whether they are to be literal or encoded and which encoding style to use |
|
<soap:fault> |
As a child of a <fault> element |
Defines the name of a SOAP fault, it’s namespace, encoded/literal and the encoding style |
|
<soap:header> |
As a child of an <input> or <output> element that’s a child of a <binding> element |
Specifies the message that this header is used with, the header namespace, encoded/literal and the encoding style |
|
<soap:headerfault> |
As a child of an <input> or <output> element that is a child of a <binding> element |
Specifies the message that this header fault corresponds to, the header fault namespace, encoded/literal and the encoding style |
|
<soap:operation> |
As a child of an <operation> element that is the child of a <binding> element |
Specifies the SOAPAction value to use when invoking this operation and whether to use RPC or document style SOAP |
The <soap:binding> element in Listing 4‑1 specifies that clients must use RPC-style SOAP over HTTP. The URI http://schemas.xmlsoap.org/soap/http indicates the HTTP protocol. This in neither a namespace nor a URL, it’s just a unique name that is defined within the context of SOAP WSDL binding to mean HTTP.
Each operation of the portType VB6WeatherSoapPort has a corresponding <operation> element inside the <binding> element. This <operation> element provides the information needed to actually invoke the operation using the specified protocol. The example in Listing 4‑1 has an <operation> element called GetTemperature with a <soap:operation> that specifies a soapAction of http://tempuri.org/action/VB6Weather.GetTemperature. It also contains an <input> and an <output> element that correspond to the operation’s input and output messages respectively. Within the <input> and <output> elements, <soap:body> elements specify that the contents of the <Body> element in the SOAP message must be part of the namespace http://tempuri.org/message/ and must be encoded according to the encoding style http://schemas.xmlsoap.org/soap/encoding/ which is the SOAP Section 5 encoding style. To summarize, here’s the information that the client gets from reading the <binding> in Listing 4‑1:
· This binding is for the portType VB6WeatherSoapPort
· To invoke operations in this binding, the client must use RPC style SOAP over HTTP
· The SOAPAction HTTP header for the GetTemperature operation is http://tempuri.org/action/VB6Weather.GetTemperature
· The contents of the <Body> element in the SOAP request should be encoded according to SOAP Section 5 and should belong to the namespace http://tempuri.org/message/
· The contents of the <Body> element in the SOAP response will be encoded according to SOAP Section 5 and will belong to the namespace http://tempuri.org/message/
Going down in Listing 4‑1 you see the <service> element which is called VB6Weather. The SOAP Toolkit’s WSDL Generator asks you for the service name and uses it as the value of the <service> name attribute it here. The <service> contains zero or more <port> elements which specify how this service can be accessed. In this example, the port refers to the binding called VB6WeatherSoapBinding and contains a <soap:address> element that tells the client where the SOAP end point is located. The client takes reads the value of the location attribute from the <soap:address> and sends the SOAP request to this location. Therefore, if this location is incorrect, the client will not be able to reach the Web service.
In this section I will take a look at the details of how WSDL describes SOAP-based Web services. Document/literal SOAP messages are commonly used and their WSDL is the simplest to understand so we’ll start with that. Next I’ll discuss the WSDL for RPC/encoded SOAP messages because this format is also commonly used especially when you are exposing existing applications as Web services. The other two formats: document/encoded and RPC/literal are rarely ever used and exist mostly because the SOAP and WSDL standards allow them. To spare you unnecessary details, I won’t discuss these two here.
You already know the definitions of the terms RPC, document, literal, and encoded within the context of SOAP messages. Let’s define these terms within the context of WSDL and using WSDL terminology.
· Document: When you are using document, you are thinking of sending an XML document with the request message and getting back an XML document with the response message. Therefore each <message> contains one or more <part>s that make up the XML document you are sending or receiving. The primary difference between document and RPC is that with document, <part>s do not correspond to method parameters, they just represent the XML document being transmitted.
· RPC: When you are using RPC, you are thinking in terms of invoking methods, passing parameters and getting return values. Therefore input and output <message>s contain <part>s that correspond to the method parameters and return value.
· Encoding within the context of WSDL: Encoding means the contents of each part will adhere to some agreed upon encoding rules such as SOAP Section 5 encoding. Each <part> has some type, but that type by itself does not provide all the information you need to serialize the data into the message. That’s why it is sometimes called an abstract part type: You need more information to make it concrete. To serialize the data, you must know the encoding rules used, which are usually the SOAP Section 5 rules. The <part> type and name attributes, and the namespace attribute of <soap:body> along with the SOAP Section 5 encoding rules, all work together to tell you how to serialize the data into the message.
· Literal within the context of WSDL: Using literal means you create a schema that describes the exact contents of each message part. Each <part> is of a type that is specified using an XSD schema. This is also called a concrete type because just by looking at the schema you can determine how to serialize the data into the message.
To explain the WSDL for document/literal and RPC/encoded, I will use the .NET Web service in Listing 4‑2 which exposes a document/literal operation called ExampleDocLit and an RPC/encoded operation called ExampleRpcEnc.
Listing 4‑2 The Example VB .NET Web service with an RPC/encoded and a document/literal method. (VBWSBook\Chapter4\Combos\Example.asmx.vb).
Public Structure theStruct
Public theName As String
Public theNumber As Double
Public theDate As Date
End Structure
Public Class Example
<WebMethod(), SoapRpcMethod()> _
Public Function ExampleRpcEnc(ByVal a As Integer, _
ByVal b As Single(), _
ByVal c As theStruct) As Object
Dim ret As Double = 9.99
Return ret
End Function
<WebMethod(), SoapDocumentMethod()> _
Public Function ExampleDocLit(ByVal a As Integer, _
ByVal b As Single(), _
ByVal c As theStruct) As Object
Dim ret As Double = 9.99
Return ret
End Function
End Class
As you learned in chapter 1, you can obtain the WSDL for a .NET Web service by navigating to the service’s .asmx file and adding WSDL as a query string. The next two sections show and explain the contents of this auto-generated WSDL beginning with the document/literal method.
Listing 4-3 shows a modified version of the auto-generated WSDL for the ExampleDocLit method in Listing 4-2. The original auto-generated WSDL contains definitions for both methods ExampleDocLit and ExampleRpcEnc. To make the WSDL easier to read, I separated the two definitions so that you can focus on each one individually. In addition, I removed the <types> section and put it in a separate listing (Listing 4-4) also to make the core WSDL easier to read.
Listing 4‑3 WSDL document for the document/literal combination. Note that the <types> section has been removed to make the document easier to read. (VBWSBook\Chapter4\ExampleWSDLs\DocLitExample.wsdl).
<definitions
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:s1="http://tempuri.org/"
targetNamespace="http://tempuri.org/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<!-- <types> section removed from here -->
<message name="ExampleDocLitSoapIn">
<part name="parameters" element="s1:ExampleDocLit" />
</message>
<message name="ExampleDocLitSoapOut">
<part name="parameters" element="s1:ExampleDocLitResponse" />
</message>
<portType name="ExampleSoap">
<operation name="ExampleDocLit">
<input message="s1:ExampleDocLitSoapIn" />
<output message="s1:ExampleDocLitSoapOut" />
</operation>
</portType>
<binding name="ExampleSoap" type="s1:ExampleSoap">
<soap:binding
transport="http://schemas.xmlsoap.org/soap/http"
style="document" />
<operation name="ExampleDocLit">
<soap:operation
soapAction="http://tempuri.org/ExampleDocLit"
style="document" />
<input>
<soap:body use="