• No results found

Using WSDL to Document Web Services

Overview

In the previous chapter, you learned how to create a schema to describe the format of a SOAP message. You can use XML Schema to describe the layout of a message and the type of data the message contains, and the resulting schema can be used to validate the message received by the Web server. However, XML Schema alone cannot fully describe a Web service.

Let’s say I have created a Calculator Web service. The Web service exposes two methods,

Add and Subtract. Both methods accept two integers and return a single integer containing the result—Add returns the sum of the two integers, and Subtract returns the difference of the two numbers.

In an effort to describe how a client will interact with my Web service, I define a schema for the messages that will be exchanged between the client and the server. My schema contains a complex type definition for the request and response messages for both the Add

and Subtract methods. Remember that the ultimate goal is not to have developers pore through schema definitions trying to decipher how to interact with a Web service. Instead, I want to describe my Web service in such a way that a tool can decipher it and create a proxy on the client’s behalf.

In addition to the information provided by the schema, what else does a client need to know in order to invoke methods exposed by the Calculator Web service? Because the body of a SOAP message can contain anything that does not invalidate the XML, individual SOAP messages can be combined to support a wide variety of message exchange patterns. The message exchange patterns for the Calculator Web service are pretty straightforward, but a formal association between the Add and Subtract request messages and their associated response messages would remove any possible ambiguity.

A formal description of the message patterns is even more important for more complex Web services. Some Web services might accept a request but not send a corresponding

response back to the client. Others might only send messages to the client.

The schema also does not contain information about how to access the Web service. Because SOAP is protocol independent, messages can be exchanged between the client and the server any number of ways. How do you know whether you should send a message over HTTP, SMTP, or some other transport protocol? Furthermore, how do you know the address to which the message should be sent?

Web Service Description Language (WSDL) is an XML-based dialect layered on top of the schema that describes a Web service. A WSDL document provides the information

necessary for a client to interact with the Web service. WSDL is extensible and can be used to describe practically any network service, including SOAP over HTTP and even prot ocols that are not XML-based, such as DCOM over UDP.

In this chapter, I build the WSDL document that describes the Calculator Web service. Along the way, I describe the various parts of a WSDL document and the roles they play in

describing the Web service.

WSDL documents can be intimidating at first glance. But the syntax of a WSDL document is not nearly as complex as that of an XML Schema document. A WSDL document is

composed of a series of associations layered on top of an XML Schema document that describes a Web service. These associations add to the size and the perceived complexity of a WSDL document. But once you look underneath the covers, WSDL documents are rather straightforward.

The root of a WSDL document is the definitions element. Within this element are five types of child elements:

§ types Contains the schema definitions of the messages that can be sent and received by the service. The most common way of representing the schema is using XML Schema.

§ message Serves as a cross-reference that associates the message with its definition within the schema.

§ portType Defines a set of interfaces that the Web service can expose. An interface is associated with one or more messages.

§ binding Associates the portType definition with a particular protocol.

§ service Defines a collection of related endpoints (ports) exposed by the Web service. The following diagram illustrates how these five elements are layered on top of the schema definition to describe the Web service:

As you can see, a WSDL document is composed of a series of associations. For example, message parts are used to associate a datatype definition with a portion of the content of a message.

definitions Element

The root element in a WSDL document, the definitions element, serves much the same role as the schema element in an XML Schema document. It contains child elements that define a particular service.

Much like an XML Schema document, a WSDL document can define its own namespace by adding a targetNamespace attribute to the definitions element. The only restriction is that the value of the targetNamespace attribute cannot contain a relative URI.

The WSDL namespace allows you to fully qualify references to entities defined within a WSDL document. For example, a message definition is referenced by a portType definition. Later in the chapter, I reference entities defined within another WSDL namespace to facilitate interface inheritance.

The following WSDL fragment defines the definitions element for the Calculator Web service: <?xmlversion="1.0"encoding="utf-8"?> <definitionstargetNamespace="http://somedomain/Calculator/wsdl" xmlns:tns="http://somedomain/Calculator/wsdl" xmlns="http://schemas.xmlsoap.org/wsdl/"> <!--Definitionswillgohere. --> </definitions>

The preceding WSDL document contains a definitions element. Within the target

namespace, the target namespace is set to http://somedomain/Calculator. Then a reference is made to the target namespace, assigning it a prefix of tns:. This prefix will be used within the document to fully qualify references to entities defined within the document. Finally, the WSDL namespace is set to the default namespace.

The definitions element defines the boundaries of a particular name scope. Elements declared within a WSDL document are used to define entities such as ports and messages. These entities are assigned a name using the name attribute. All name attributes within a name scope must be unique. For example, if a WSDL document contains a port named Foo, it cannot contain another port or message named Foo.

It might not always be practical to define a unique fully qualified URI for a namespace—for example, early in the development cycle or when you want to create a couple of

experimental Web services. In these cases, you can use http://tempuri.org, a special URI that is used by convention to define namespaces that do not need to be uniquely identified.

types Element

The types element contains schema information referenced within the WSDL document. The default type system supported by WSDL is XML Schema. If XML Schema is used to define the types contained within the types element, the schema element will appear as an immediate child element.

You can use other type systems by extension. If you use another type system, an

extensibility element can appear under the types element. The name of the element should identify the type system used. In this chapter, I limit my discussion to XML Schema because it is the dominant type system used in WSDL documents, including those for Web services developed on the .NET platform.

The Calculator Web service will expose two RPC-style methods, an Add method and a

Subtract method. The messages will be encoded in much the same way that I showed you in

Chapter 4. The only difference is that the schema will be embedded within a WSDL document, as shown here:

<?xml version="1.0" encoding="utf-8"?>

xmlns:tns="http://somedomain/Calculator/wsdl" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:s="http://somedomain/Calculator/schema" xmlns="http://schemas.xmlsoap.org/wsdl/"> <types> <schema attributeFormDefault="qualified" elementFormDefault="qualified" xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://somedomain/Calculator/schema">

<!-- Definitions for both the Add and Subtract SOAP messages - ->

<element nam e="Add"> <complexType> <all>

<element name="x" type="int"/> <element name="y" type="int"/> </all> </complexType> </element> <element name="AddResult"> <complexType> <all>

<element name="result" type="int"/> </all> </complexType> </element> <element name="Subtract"> <complexType> <all>

<element name="x" type="int"/> <element name="y" type="int"/> </all> </complexType> </element> <element name="SubtractResult"> <complexType> <all>

</all>

</complexType> </element>

<!-- Common SOAP fault detail element used by Add and Subtract -->

<element name="CalculateFault"> <complexType>

<all>

<element name="x" type="int"/> <element name="y" type="int"/>

<element name="Description" type="string"/> </all>

</complexType> </element>

</schema> </types>

<!-- More definitions will go here. -->

</definitions>

Within the types element are schema definitions for the Add and Subtract methods, which use the reference to the schema’s namespace that appears within the definitions element earlier in the document.

WSDL is not limited to describing XML-based serialization formats. You can use it to describe services that use other formats, including binary. For example, you can use WSDL to describe a service exposed via DCOM. In this case, you can still use XML Schema to describe the data being sent across the wire. The WSDL specification provides the following recommendations for doing so:

§ Describe the data using elements, not attributes. For example, each parameter should be encoded within its own element, much like in SOAP Encoding.

§ Describe only data that is related to the message and is not particular to the wire encoding. For example, the parameters passed to a remote COM object should be described in the schema. However, the DCOM object identifier (OID) is wire-protocol- specific data that identifies the object and should not be described in the schema.

§ Array types should be derived from the Array complex type defined in the SOAP Encoding schema. By convention, the name of the type should be the type of items within the array, prefixed by ArrayOf.

§ Parameters that can contain data of any type should be defined by an element of type

xsd:anyType.

The message element provides a common abstraction for messages passed between the client and the server. Because you can use multiple schema- definition formats within a WSDL document, it is necessary to have a common way of identifying the messages. The

message element provides this common level of abstraction that will be referenced in other parts of the WSDL document.

Multiple message elements can and often do appear in a WSDL document, one for each message being communicated between the client and the server. Each message contains one or more part elements that describe pieces of content within the message. An example of a part is the body of a SOAP message or a parameter contained within the query string, a parameter encoded in the body of a SOAP message, or the entire body of a SOAP

message.

Each part element contains attributes that associate type and element definitions found in the types element. Because parts are abstract definitions of content, the binding information must be examined in order to determine the meaning of the parts.

Two attributes that can appear within the part element are the element and type attributes. The element attribute refers to an element definition in a schema. The type attribute refers to a type definition in a schema.

Because the Calculator Web service contains two methods, each with a request and response message, and a fault message was defined, the WSDL document will contain five

message elements:

<?xml version="1.0" encoding="utf-8"?>

<definitions targetNam espace="http://somedomain/Calculator/wsdl" xmlns:tns="http://somedomain/Calculator/wsdl"

xmlns:s="http://somedomain/Calculator/schema" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/">

<!-- Type definitions removed for clarity -->

<message name="AddMsgIn">

<part name="parameters" element="s:Add"/> </message>

<message name="AddMsgOut">

<part name="parameters" element="s:SubtractResult"/> </message>

<message name="SubtractMsgIn">

<part name="parameters" element="s:Add"/> </message>

<message name="SubtractMsgOut">

<part name="parameters" element="s:SubtractResult"/> </message>

<message name="CalculateFaultMsg">

</message>

<!-- More definitions will go here. -->

</definitions>

I created a message element for the request and response message of the Add and

Subtract methods. I could have instead specified a part element for each parameter. For example, the AddMsgIn message could have been written as follows:

<message name="AddMsgIn">

<part name="x" type="xsd:int"/> <part name="y" type="xsd:int"/> </message>

Parameters x and y are contained within their own part of the message. The protocol binding will have a lot of influence over how messages are represented. When I discuss binding later in the chapter, I will represent each parameter contained within an HTTP query string as its own message part.

Because each part can serve as an abstract definition of a piece of data, a message can be composed of multiple pieces of data from multiple sources. Although it is not recommended, you could describe a message in which some of the parameters were encoded within a SOAP body and some of the parameters were encoded within the query string.

portType Element

The portType element contains a set of abstract operations representing the types of correspondences that can occur between the client and the server. For RPC-style Web services, a portType can be thought of as an interface definition in which each method can be defined as an operation.

A port type is composed of a set of operation elements that define a particular action. The

operation elements are composed of the messages defined within the WSDL document. WSDL defines four types of operations, known as operation types:

§ Request-response RPC-style communication in which the client makes a request and the server issues a corresponding response.

§ One-way Document-style communication in which the client sends a message but does not receive a response from the server indicating the result of the processed message.

§ Solicit-response The opposite of the request-response operation. The server sends a request, and the client sends back a response.

§ Notification The opposite of the one-way operation. The server sends a document- style communication to the client.

An operation is composed of a subset of input, output, and fault elements. The type of elements and the ordering of the elements within the operation determine the type of operation. For example, one-way defines an input message, and request-response defines an input and an output message. The solicit-response and the notification operation types are the opposite of request-response and one-way, respectively. The solicit-response operation lists the output message and then the input message, and the notification operation contains an output message instead of an input message.

Table 5-1 lists the type and ordering of messages for each operation type.

Table 5-1: Message Ordering for Operation Types Operation

Type

input output fault

Request- response 1 2 31 One-way 1 Solicit- response 2 1 31 Notification 1

1. The fault message is optional. Any number of fault messages can appear in an operation.

Operations involving two-way communication can optionally specify one or more fault messages. Like Java method definitions, fault messages allow you to declare the type of exceptions that can be thrown by the server application. However, the list of possible faults should not include errors that are specified by the underlying transport protocol. For example, you would not need to represent the HTTP 500 error in the WSDL document. The names of the input,output, and fault elements have a default value if one was not specified. For one-way and notification operation types, the default name is the name of the

operation element in which they are contained. For request-response operation types, the name of the input and output elements default to the name of the operation with Request or

Response appended to the end. For solicit-response, the name of the output element defaults to the name of the operation with Solicit or Response appended to the end.

Because multiple fault elements can be defined within an operation, there is no default name for the fault element. Therefore, each fault element must be uniquely named within its parent

operation element.

Here is the portType definition for the Calculator Web service: <?xml version="1.0" encoding="utf-8"?>

<definitions targetNamespace="http://somedomain/Calculator/wsdl" xmlns:tns="http://somedomain/Calculator/wsdl"

xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/">

<!-- Type and message definitions removed for clarity -->

<portType name="CalculatorPortType"> <operation name="Add">

<input message="tns:AddMsgIn"/> <output message="tns:AddMsgOut"/>

<fault message="tns:CalculateFaultMsg" name="CalculateFault"/> </operation>

<operation name="Subtract">

<input message="tns:SubtractMsgIn"/> <output message="tns:SubtractMsgOut"/>

<fault message="tns:CalculateFaultMsg" name="CalculateFault"/> </operation>

</portType>

<!-- More definitions will go here. -->

</definitions>

The preceding snippet of the Calculator WSDL document defines the portType named

CalculatorPortType. It contains two request-response operations, Add and Subtract. Because the operations are of type request-response, they both define an input and an output message. Both operations also contain a fault element named CalculateFault.

Related documents