Building Industry Standard WSDL

 

Scott Seely
Microsoft Corporation

February 4, 2002

Download Service02062002.exe.

Introduction

In this column, we will look at the benefits and uses of standardizing the interface to a Web Service. The biggest benefit of a standardized interface for clients is that once an application is written to speak to that interface, it can talk to any Web Service that implements that interface. This builds on the framework provided by SOAP. Before we get into the details of standardizing a Web Service interface, let’s take a quick look at the development of the WSDL specification.

SOAP was created to solve the interoperability problems between components written in different languages, running on different platforms, and connected only by the Internet. As soon as SOAP gained a little mindshare, the early adopters noticed that simply showing sample valid messages was not enough. Most of these people had worked with interface definition languages and knew the benefits of those descriptions. The descriptions allow the implementer of the code to define how a user of that code can interact with it. Without these definitions, people wind up wasting a lot of time trying to figure out just what combination of inputs makes the Web Service work.

To fill this need, several XML-based IDLs were created. Microsoft proposed the Service Description Language (SDL), IBM proposed the Network-Accessible Service Specification Language (NASSL), and others proposed other ideas. The groups then came together and agreed on a common IDL: WSDL. The WSDL specification describes an XML Schema that conveys all of this information to the user.

A WSDL document can be logically divided into two sections:

  • Abstract definitions: defines things like datatypes, messages, and the way messages can be combined as request/response pairs for RPC-like operations.
  • Concrete definitions: defines how the messages will be sent using a particular protocol, such as SOAP or HTTP-GET.

In addition, the optional service element documents where to access a particular group of messages. All of this information combines to describe a Web Service so that someone else can use the endpoint.

Today, many different organizations are creating Web Services. The early adopters are learning their lessons as far as what does and does not work with this new technology, and many companies are getting big wins by integrating their heterogeneous environments using SOAP and Web Services. Applications that act as clients to Web Services typically have to be customized for each Web Service they talk to. This is true even if the client talks to Web Services that provide similar functionality. These slight differences cause problems and show that clients can reap big benefits if organizations implementing similar services could agree on a common standard.

The first such standard way to share data has been in existence for over a year: UDDI. UDDI, the Universal Description, Discovery, and Integration registry is a standardized Web Service. The WSDL has been defined and works quite well for the UDDI site operators who have implemented the code behind the WSDL-defined interface.

Over the next few columns, Matt Powell and I will take a look at what we see to be the role of WSDL with respect to standardization. In this column, I will discuss the various ways in which to create standards and provide some guidelines for what those standards should and should not contain. As a wrap-up, we will look at an example of developing a standard through a standards body.

I've included a number of links at the end of this column for further reading. If you need to do anything covered in this article, browse those links.

Standards Development

Standards themselves typically come into being in one of two different ways: a group organizes to define the standard, or one organization's implementation becomes the standard by default. Standards organizations such as ANSI, ISO, and the W3C represent examples of the groups who organize to define what a standard is. The second type of standard is commonly referred to as a "de facto" standard. Let's take a quick look at how both types of standards come into being.

Through a Standards Body

Often, the right place to standardize something is through a standards body. These bodies typically have influence within a particular industry, have contact information for the standards people at member organizations, and have experience in achieving consensus amongst members. Sometimes, these bodies are respected industry organizations that publish and maintain standards as one of their many duties.

Some of the larger organizations related to the IT industry include:

There are other organizations, and I have no doubt slighted someone's favorite.

Other standards bodies are formed out of nothingness to agree on a single implementation. The group of companies defining the UDDI specification formed in this way. Typically, the individuals in the groups that form the standards are subject matter experts who are actively architecting and applying the technologies being defined. The end result is often a specification in which the vast majority of items are well defined and useful. Those participating in the standardization effort benefit by ensuring that their concerns are addressed by the standard.

Look at what has happened with this columnist's favorite protocol, SOAP. The timeline looks something like this: A group of companies worked together to create SOAP v0.9. These companies included DevelopMentor, UserLand, and Microsoft. By the time SOAP v1.1 was drafted, many more companies had joined the effort. Today, SOAP v1.2 is being drafted within the auspices of the W3C. It will become an official standard, a W3C Recommendation.

De Facto Standards

Other standards occur because "it's the way things are done." When IBM defined what their version of a personal computer should look like and how components should talk to each other, many other companies were able to come on board and put together clones of the IBM machine. No standardization effort occurred. Instead, others simply mimicked what IBM had done. The IBM PC became a de facto standard.

This happened for two big reasons: IBM was able to capture a lot of market share, and Microsoft was able to license its operating system to others. Off-the-shelf motherboards, memory, and video cards could be put together with other components to make a computer that would run the same applications that ran on an IBM PC. Later, the communication mechanisms and other items were standardized by official organizations. ISA, EISA, SCSI, ATA, and other interfaces have been written up and described in excruciating detail.

De facto standards occur in many different industries. Here's an example that I have locked away in my memory. (This retelling isn't exact, but gets the idea across.) A long line of de facto standards cooperated to dictate why the NASA space shuttle engines are a certain size. The engines are crafted to be able to ride on trains from one side of the country to another. The width of train tracks is the same throughout the United States, and tunnels have certain minimum heights and widths. So, the engines have to fit through those tunnels while riding on a train car. Nobody got together to decide how wide the tracks would be. Instead, the first trains were created based on widths common in Europe.

Now the distance between train tracks in Europe happens to be about the same width as the wooden rails that supported horse-drawn wagons in mines. Again, no group got together to decide how far apart to place the wagon wheels or rails. The distance between wagon wheels is the same width as what the chariots the Romans used all over the Roman Empire, which at one time stretched into England. The width of those chariots was determined by the wheelbase used for chariots that had two horses, side by side. No group collaborated to decide how wide a horse's backside should be. We laid thousands of miles of track all over the United States (and other places on Earth), and the width of the track was based on a de facto standard—which ultimately dictated the size of NASA space shuttle engines—the width of a horse's backside!

When creating a Web Service, it will often prove useful to investigate what standards exist for the problem you are addressing. If none exist, decide whether it might be helpful to have the Web Service used by others in your industry. For example, if the Web Service fulfills a request your customers are making, odds are pretty good that your competitors are being asked for the same thing. Take a proposal on how to handle the request in a uniform manner to an organization that represents your industry. This will make your clients happy, because they can use something that has been standardized. The standardization can reduce the cost of supporting multiple proprietary systems. If you happen to be leading the effort, this gets you some positive attention as well.

Guidelines

So, what are some general guidelines in creating a standard? Obviously, you want to do some initial work before presenting your ideas. First, create a working example of the idea. Design the interface to be useful for the target audience. This point is pretty important: concentrate on what the data will look like on the wire, not on how you will generate the service behind that WSDL using your favorite toolkit. By thinking about the interface instead of the implementation, you will have interoperability at the front of your mind instead of whatever is convenient with your toolkit.

After some refinement, you should have a chunky instead of chatty interface. What's a "chunky" interface? A chunky interface prefers to send too much data instead of forcing the client to send several more targeted messages to get required data back. For example, retrieving an order might return customer data as well, just to save the extra call. Why would you do this? Since a Web Service message may have high network latency, chunky calls are preferable.

Once this is done, document everything and work up a proposal for a standard. You have a lot of examples to look at. The documentation created for UDDI offers a good example of the types of documents you need to create, and the level of detail you need to present.

With the initial documentation in hand, you are ready for the next and biggest step: standardization. Take this step if you think that the WSDL will benefit others, and that you will gain some advantage from formally standardizing the Web Service. Identify the standards bodies you want to work with. More often than not, you will find yourself working with an industry organization instead of a larger standards organization, such as ECMA or the W3C.

In a previous job, I worked for a company that wanted to create a uniform representation of cardiac data. To decide how data would be presented, that company (and many others) worked with the American Heart Association to define the data that would be captured and how to present it for data collectors. Most industries have a unifying association to which interested organizations belong. To decide what organization you should work with, figure out what organization(s) might be interested in the format, and work through them to get things in motion. You may discover that a similar standard is already being worked on, or that multiple proposals already exist. Don't despair. This is why you went to the organization in the first place: to get agreement amongst others in the industry.

Because of your effort, you will have helped define how the Web Service works. The benefit of all this work is that your company receives recognition as a leader in the field. Let's take a look at a simple example of how this whole process might work.

The Pencil Inspection and Ordering Standard (PIOS)

Many of the examples Matt and I use seem to revolve around office supplies. Just about everybody understands the items we are talking about. This allows us to frame the discussion and to explain the underlying principals with simple examples.

For this example, we will create a specification as a candidate for standardization that specifies how a client application could discover what types of pencils you have available. Then, the client application will be able to place orders using the same interface. Clients for this interface will be office supply retailers and wholesalers. By defining a standard way of placing orders, companies such as pencil manufacturers and importers could expose the same interface. Wholesalers and retailers would then use the interface as clients to automate a large portion of their ordering process. For example, a process could track on-hand supplies of a given pencil. When the supply reaches a certain level, such as 100 pencils left, the system could place an order for 1000 more of the same item. This code would only need to know where to place orders. The rest of the code would be able to stay the same between various wholesalers and retailers.

So, what should we look at? The interface itself needs to support browsing of the pencil types as well as a way to order them. Pencils have several different properties that people might want to search on. The permutations of pencil types alone mean that the browsing API needs to allow for some fairly sophisticated queries. A pencil has the following properties:

  • Type: Mechanical or "regular."
  • Hardness: No. 2, No. 3, and so on.
  • Color: Black, red, blue, green, and so on.
  • Pencil width (in inches): Novelty pencils can be extra wide or extra narrow.
  • Pencil length (in inches): Not all pencils are the same length.
  • Image location: Allows the user to actually see what the pencil looks like. This would only be useful for applications that can display an image. This includes user interfaces, as well as creation of a catalog.
  • Manufacturer.
  • Style Name: Identifies the pencil as named by the manufacturer.
  • Product ID: Uniquely identifies the pencil for the supplier.

That's a lot of information that you can use to describe a simple pencil. Because of this, the API needs to give a client some way to search through the catalog. These searches will limit the number of pencil types the client receives. In order to perform a search, the Web Service should have a method of presenting the searchable terms.

Once we have set up the ways to browse available pencils, we just have to set up a method for customers to order the pencils they want, and to track their order until it ships from the pencil seller.

Now that we know what we want, let's design the Web Service. For the sake of brevity, we will assume that some other standard already exists that allows a customer to register themselves, discover or validate their ID, and so on. We will also assume that some other standard exists for processing payment information. This example only concentrates on the discovery and ordering of pencils.

Because we want to do a good job separating the data, binding, and endpoint information, the full description of a given endpoint will be placed in three files. There are a few ways to look at what data types are required. The way I typically do things is to look at what functionality I need to support, and then derive the necessary data types from the operations I will be exposing. This particular Web Service will expose the following functions:

  • GetSearchValues: Retrieves the values you might use to search for items available from a particular implementation of the Web Service.
  • Search: Allows users to submit search criteria to the particular implementation of the Web Service. This then returns the instances of all pencils matching all of the criteria.
  • PlaceOrder: Allows customers to place orders. This relies on some other existing way for customers to identify themselves to this Web Service.
  • TrackOrder: Given an order ID, this method allows users to find out the current status of their orders.

The XML Schema describing all of this will use a set of common namespaces. To avoid bloating the size of this article, here is just the opening element in the XSD declaration:

<xsd:schema xmlns:tns="http://pencilsellers.org/pencil" 
    targetNamespace="http://pencilsellers.org/pencil" 
    id="pencilSchema" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:wsdl="https://schemas.xmlsoap.org/wsdl/"
    xmlns:soapenc="https://schemas.xmlsoap.org/soap/encoding/">

The first item we know we will need is a pencil description. To handle the description of properties mentioned above, the schema should look like this:

<xsd:complexType name="Pencil">
    <xsd:sequence>
        <xsd:element minOccurs="1" maxOccurs="1" name="type"
            type="xsd:string" />
        <xsd:element minOccurs="1" maxOccurs="1" name="hardness" 
            type="xsd:int" />
        <xsd:element minOccurs="1" maxOccurs="1" name="width" 
            type="xsd:float" />
        <xsd:element minOccurs="1" maxOccurs="1" name="length" 
            type="xsd:float" />
        <xsd:element minOccurs="1" maxOccurs="1" name="imageURL" 
            type="xsd:string" />
        <xsd:element minOccurs="1" maxOccurs="1" name="manufacturer" 
            type="xsd:string" />
        <xsd:element minOccurs="1" maxOccurs="1" name="styleName" 
            type="xsd:string" />
        <xsd:element minOccurs="1" maxOccurs="1" name="productID" 
            type="xsd:string" />
    </xsd:sequence>
</xsd:complexType>

Knowing what a pencil is, we also know what items can be searched on. If the user knows the product ID, we can assume that they will be ready to order the product. We can assume that the user will not search on the pencil's image URL either. A user can search on the following items: pencil type, lead hardness, width, length, pencil manufacturer, and pencil style. To communicate this information, we need to pass arrays of strings, integers, and floats. The search terms are then packaged into a complex type, PencilSearchValues.

<xsd:complexType name="PencilSearchValues">
    <xsd:sequence>
        <xsd:element minOccurs="1" maxOccurs="1" name="typeValues" 
            type="tns:ArrayOfString" />
        <xsd:element minOccurs="1" maxOccurs="1" name="hardnessValues" 
            type="tns:ArrayOfInt" />
        <xsd:element minOccurs="1" maxOccurs="1" name="widthValues" 
            type="tns:ArrayOfFloat" />
        <xsd:element minOccurs="1" maxOccurs="1" name="lengthValues" 
            type="tns:ArrayOfFloat" />
        <xsd:element minOccurs="1" maxOccurs="1" 
            name="manufacturerValues" type="tns:ArrayOfString" />
        <xsd:element minOccurs="1" maxOccurs="1" name="styleNameValues" 
            type="tns:ArrayOfString" />
    </xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ArrayOfString">
    <xsd:complexContent mixed="false">
        <xsd:restriction base="soapenc:Array">
            <xsd:attribute wsdl:arrayType="xsd:string[]" 
                ref="soapenc:arrayType" />
        </xsd:restriction>
    </xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="ArrayOfInt">
    <xsd:complexContent mixed="false">
        <xsd:restriction base="soapenc:Array">
            <xsd:attribute wsdl:arrayType="xsd:int[]" 
                ref="soapenc:arrayType" />
        </xsd:restriction>
    </xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="ArrayOfFloat">
    <xsd:complexContent mixed="false">
        <xsd:restriction base="soapenc:Array">
            <xsd:attribute wsdl:arrayType="xsd:float[]" 
                ref="soapenc:arrayType" />
        </xsd:restriction>
    </xsd:complexContent>
</xsd:complexType>

Having decided what the search terms are, how does a user perform a search? Odds are that users interacting with a client application will not know the exact dimensions of the pencil they are looking for, or the complete name of the pencil. They may also want to search using more than one item. For example, a search might say to return all pencils whose length is between 5 and 6 inches. You can do this by sending in multiple search terms, and by identifying what the given condition maps to.

To define the type of comparison, the ComparisonType enumeration was created. This enumeration contains identifiers for the following operations: <, <=, =, >=, >. Another enumeration, SearchValueType, defines the value being searched for. I wanted a way for a client to send a comparison request where the value being compared is transmitted as a string. What it compares against determines how to interpret that value.

The other option would have been to create several comparison operations: one each for strings, floats, and integers. This would have made it more difficult to extend the interface in the future. These two enumerations, plus the generic string, are utilized by the SearchTerm type. The Search Web Method takes an array of SearchTerm items and uses those to create a query and find the requested pencils. The XSD definitions for these items are as follows:

<xsd:complexType name="ArrayOfSearchTerm">
    <xsd:complexContent mixed="false">
        <xsd:restriction base="soapenc:Array">
        <xsd:attribute wsdl:arrayType="tns:SearchTerm[]" 
            ref="soapenc:arrayType" />
        </xsd:restriction>
    </xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="SearchTerm">
    <xsd:sequence>
        <xsd:element minOccurs="1" maxOccurs="1" name="valueType" 
            type="tns:SearchValueType" />
        <xsd:element minOccurs="1" maxOccurs="1" name="searchValue" 
            type="xsd:string" />
        <xsd:element minOccurs="1" maxOccurs="1" name="compType" 
            type="tns:ComparisonType" />
    </xsd:sequence>
</xsd:complexType>
<xsd:simpleType name="SearchValueType">
    <xsd:restriction base="xsd:string">
        <xsd:enumeration value="Type" />
        <xsd:enumeration value="Hardness" />
        <xsd:enumeration value="Width" />
        <xsd:enumeration value="Length" />
        <xsd:enumeration value="Manufacturer" />
        <xsd:enumeration value="StyleName" />
    </xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ComparisonType">
    <xsd:restriction base="xsd:string">
        <xsd:enumeration value="lessThan" />
        <xsd:enumeration value="lessThanOrEqual" />
        <xsd:enumeration value="equal" />
        <xsd:enumeration value="greaterThanOrEqual" />
        <xsd:enumeration value="greaterThan" />
    </xsd:restriction>
</xsd:simpleType>

Now that we have a way for users to find what they are looking for, we still have to allow them to create orders. An order line consists of a product ID and a quantity to order. To keep the interface "chunky" instead of "chatty," users submit an entire order at once. The OrderItem type defines a particular order, and ArrayOfOrderItem defines what the array of these items should look like.

<xsd:complexType name="ArrayOfOrderItem">
    <xsd:complexContent mixed="false">
        <xsd:restriction base="soapenc:Array">
        <xsd:attribute wsdl:arrayType="tns:OrderItem[]"
            ref="soapenc:arrayType"  />
        </xsd:restriction>
    </xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="OrderItem">
    <xsd:sequence>
        <xsd:element minOccurs="1" maxOccurs="1" name="productID" 
            type="xsd:string" />
        <xsd:element minOccurs="1" maxOccurs="1" name="quantity" 
            type="xsd:int" />
    </xsd:sequence>
</xsd:complexType>

Finally, we need to look at the tracking data. Instead of tying into a specific tracking system such as UPS or FedEx, the tracking will simply state the order status. For our purposes, the order can be in one of the following states:

  • Inactive: The order exists but hasn't begun processing yet.
  • Active: The order is being processed, but may be in between stages.
  • Picking: Someone is grabbing the pencils for the order and placing them into a shipping container.
  • Packing: Packing materials are being added to the box. The box is being taped and addressed as well.
  • Shipped: The package has been handed off to a carrier for delivery to the customer.

To express these states in XSD, an enumeration was chosen: OrderStatus.

<xsd:simpleType name="OrderStatus">
    <xsd:restriction base="xsd:string">
        <xsd:enumeration value="Inactive" />
        <xsd:enumeration value="Active" />
        <xsd:enumeration value="Picking" />
        <xsd:enumeration value="Packing" />
        <xsd:enumeration value="Shipped" />
    </xsd:restriction>
</xsd:simpleType>

For this standardized set of WSDL, we also want to separate the operations being performed on the Web Service. The GetSearchValues and Search operations are related to discovery, whereas PlaceOrder and TrackOrder handle order related operations. To make this distinction clear, the two sets of operations will be placed into two separate port descriptions.

GetSearchValues takes no arguments and returns a PencilSearchValues element. Search will take an array of SearchTerm elements and return Pencil elements. The complete WSDL for these two items looks like this:

<?xml version="1.0" encoding="utf-8"?>
<definitions 
    xmlns:soap="https://schemas.xmlsoap.org/wsdl/soap/" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns:pencil="http://pencilsellers.org/pencil" 
    xmlns:tns="http://pencilsellers.org/pencil/discovery" 
    targetNamespace="http://pencilsellers.org/pencil/discovery" 
    xmlns="https://schemas.xmlsoap.org/wsdl/">
  <import namespace="http://pencilsellers.org/pencil" 
      <!-- The location change is a "hack" that will be used
           in following articles to make it easy to import this
           as a WSDL document. Normally, the location would
           point to a publically available URL-->
      location="https://localhost/PencilSellers.Org/PencilService.xsd" />
  <types />
  <message name="GetSearchValuesSoapIn" />
  <message name="GetSearchValuesSoapOut">
    <part name="GetSearchValuesResult" 
        type="pencil:PencilSearchValues" />
  </message>
  <message name="SearchSoapIn">
    <part name="searchTerms" type="pencil:ArrayOfSearchTerm" />
  </message>
  <message name="SearchSoapOut">
    <part name="SearchResult" type="pencil:ArrayOfPencil" />
  </message>
  <portType name="DiscoveryBinding">
    <operation name="GetSearchValues">
      <documentation>Retrieves the values you might use to search 
      for items available from a particular implementation of the 
      Web Service.</documentation>
      <input message="tns:GetSearchValuesSoapIn" />
      <output message="tns:GetSearchValuesSoapOut" />
    </operation>
    <operation name="Search">
      <documentation>Allows the user to submit a set of search 
      criteria to the particular implementation of the Web 
      Service. This then returns the instances of all Pencils 
      matching all of the criteria.</documentation>
      <input message="tns:SearchSoapIn" />
      <output message="tns:SearchSoapOut" />
    </operation>
  </portType>
  <binding name="DiscoveryBinding" type="tns:DiscoveryBinding">
    <soap:binding transport="https://schemas.xmlsoap.org/soap/http" 
        style="rpc" />
    <operation name="GetSearchValues">
      <soap:operation 
        soapAction="http://pencilsellers.org/pencil/GetSearchValues" 
        style="rpc" />
      <input>
        <soap:body use="encoded" 
            namespace="http://pencilsellers.org/pencil/discovery" 
            encodingStyle="https://schemas.xmlsoap.org/soap/encoding/" />
      </input>
      <output>
        <soap:body use="encoded" 
            namespace="http://pencilsellers.org/pencil/discovery" 
            encodingStyle="https://schemas.xmlsoap.org/soap/encoding/" />
      </output>
    </operation>
    <operation name="Search">
      <soap:operation soapAction="http://pencilsellers.org/pencil/Search" 
        style="rpc" />
      <input>
        <soap:body use="encoded" 
            namespace="http://pencilsellers.org/pencil/discovery" 
            encodingStyle="https://schemas.xmlsoap.org/soap/encoding/" />
      </input>
      <output>
        <soap:body use="encoded" 
            namespace="http://pencilsellers.org/pencil/discovery" 
            encodingStyle="https://schemas.xmlsoap.org/soap/encoding/" />
      </output>
    </operation>
  </binding>
</definitions>

The same thing is then done for the operations related to actually placing an order.

<?xml version="1.0" encoding="utf-8"?>
<definitions 
    xmlns:soap="https://schemas.xmlsoap.org/wsdl/soap/" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns:pencil="http://pencilsellers.org/pencil" 
    xmlns:tns="http://pencilsellers.org/pencil/order" 
    targetNamespace="http://pencilsellers.org/pencil/order" 
    xmlns="https://schemas.xmlsoap.org/wsdl/">
  <import namespace="http://pencilsellers.org/pencil" 
      <!-- The location change is a "hack" that will be used
           in following articles to make it easy to import this
           as a WSDL document. Normally, the location would
           point to a publically available URL-->
      location="https://localhost/PencilSellers.Org/PencilService.xsd" />
  <types />
  <message name="PlaceOrderSoapIn">
    <part name="CustomerID" type="s:string" />
    <part name="items" type="pencil:ArrayOfOrderItem" />
  </message>
  <message name="PlaceOrderSoapOut">
    <part name="PlaceOrderResult" type="s:string" />
  </message>
  <message name="TrackOrderSoapIn">
    <part name="orderID" type="s:string" />
  </message>
  <message name="TrackOrderSoapOut">
    <part name="TrackOrderResult" type="pencil:OrderStatus" />
  </message>
  <portType name="OrderBinding">
    <operation name="PlaceOrder">
      <documentation>Allows a customer to place an order. 
      This relies on some other existing way for the customer 
      to identify themselves to this Web Service.</documentation>
      <input message="tns:PlaceOrderSoapIn" />
      <output message="tns:PlaceOrderSoapOut" />
    </operation>
    <operation name="TrackOrder">
      <documentation>Given an order ID, this method allows the 
      user to find out the current status of their 
      order.</documentation>
      <input message="tns:TrackOrderSoapIn" />
      <output message="tns:TrackOrderSoapOut" />
    </operation>
  </portType>
  <binding name="OrderBinding" type="tns:OrderBinding">
    <soap:binding transport="https://schemas.xmlsoap.org/soap/http" 
        style="rpc" />
    <operation name="PlaceOrder">
      <soap:operation 
        soapAction="http://pencilsellers.org/pencil/PlaceOrder" 
        style="rpc" />
      <input>
        <soap:body use="encoded" 
            namespace="http://pencilsellers.org/pencil/order" 
            encodingStyle="https://schemas.xmlsoap.org/soap/encoding/" />
      </input>
      <output>
        <soap:body use="encoded" 
            namespace="http://pencilsellers.org/pencil/order" 
            encodingStyle="https://schemas.xmlsoap.org/soap/encoding/" />
      </output>
    </operation>
    <operation name="TrackOrder">
      <soap:operation 
        soapAction="http://pencilsellers.org/pencil/TrackOrder" 
        style="rpc" />
      <input>
        <soap:body use="encoded" 
            namespace="http://pencilsellers.org/pencil/order" 
            encodingStyle="https://schemas.xmlsoap.org/soap/encoding/" />
      </input>
      <output>
        <soap:body use="encoded" 
            namespace="http://pencilsellers.org/pencil/order" 
            encodingStyle="https://schemas.xmlsoap.org/soap/encoding/" />
      </output>
    </operation>
  </binding>
</definitions>

An endpoint referencing these documents would be pretty short:

<?xml version="1.0" encoding="utf-8"?>
<definitions 
    xmlns:soap="https://schemas.xmlsoap.org/wsdl/soap/" 
    xmlns:i1="http://pencilsellers.org/pencil/order" 
    xmlns:s="http://www.w3.org/2001/XMLSchema" 
    xmlns:soapenc="https://schemas.xmlsoap.org/soap/encoding/"
    xmlns:i0="http://pencilsellers.org/pencil/discovery" 
    xmlns:tns="http://pencilsellers.org/pencil" 
    targetNamespace="http://pencilsellers.org/pencil" 
    xmlns="https://schemas.xmlsoap.org/wsdl/">
  <import namespace="http://pencilsellers.org/pencil/discovery" 
    location="https://localhost/PencilSellers.org/PencilDiscovery.WSDL" />
  <import namespace="http://pencilsellers.org/pencil/order" 
    location="https://localhost/PencilSellers.org/PencilOrder.WSDL" />
  <types />
  <service name="PencilService">
    <port name="OrderBinding" binding="i1:OrderBinding">
      <soap:address 
        location="https://localhost/Simple/PencilService.asmx" />
    </port>
    <port name="DiscoveryBinding" binding="i0:DiscoveryBinding">
      <soap:address 
        location="https://localhost/Simple/PencilService.asmx" />
    </port>
  </service>
</definitions>

The above endpoint description shows the benefits of standardization. This WSDL contains no information about types, bindings, or any other particulars. It just states where two endpoints happen to reside. A developer of an endpoint gets to rely on already well-known binding descriptions when creating the service. Once the standard is defined and accepted, new implementations get the benefit of being accessible to existing clients. The clients just need to know the new implementation's URL, and they can connect. Assuming that the client application allows the Web Service URL to be defined dynamically, no code changes should be needed in order to go from one instance of the Web Service to another. In the end, this is why standardization can be a good idea.

This example did skip a number of work-intensive items for the sake of brevity. Check out the UDDI home page to get more information on what the API documentation should look like. It's probable that your documentation will look different, but it will need to provide a similar level of detail.

Summary

If you work in an industry where cooperation with others is necessary (insurance, healthcare, business-to-consumer sales, business-to-business transactions, and the like), you will want to look at using Web Services for communication. Once you get something that works well, consider the possibilities for standardizing what you did for your industry. Such an action can cast your organization as a leader, and as cooperative. Of course, there is nothing wrong with following the lead of others, and adopting standardized work, or with helping flesh out a standard that another originally proposed. Either way, the standard will benefit your customers by giving them more choice. It will help you out by allowing your business to work with a wider variety of partners.

In our next article, Matt Powell will show how to take the Pencil WSDL and convert it into a live endpoint.

Further Reading

 

At Your Service

Scott Seely is a member of the MSDN Architectural Samples team. Besides his work there, Scott is the author of SOAP: Cross Platform Web Service Development Using XML (Prentice Hall—PTR) and the lead author for Creating and Consuming Web Services in Visual Basic (Addison-Wesley).