O nce a Web Service has been deployed, potential users must be able to discover where it is and how it works. DISCO is a Microsoft® technology for publishing and discovering Web Services. Universal Description, Discovery, and Integration (UDDI) is an industry-wide initiative that defines a SOAP-based protocol for updating and querying Web Service information repositories. Like DISCO, UDDI makes it possible to publish and discover a Web Service, maximizing the site's reach and ultimate success. This column will introduce you to both of these technologies and discuss their strengths and weaknesses.
Introduction to Web Service Technologies
Web Services are all the rage these days, especially now that there is such extensive support for them in the Microsoft .NET Framework. Using .NET technologies, developers can implement Web Services through ASP.NET projects (.asmx) or through more direct, hands-on IHttpHandler implementations (.ashx). Both approaches provide the necessary infrastructure for sending and receiving XML-based messages over HTTP, which is the protocol at the heart of Web Services.
A Web Service is an application designed for machine consumption, typically built using XML with HTTP as the transport protocol because of its widespread availability. XML is used because of its flexible cross-platform support and its ability to add type and structure to the message payloads.
XML 1.0 defines the universally supported transfer syntax and XML Schema defines XML's type system. Together these technologies make it possible to map between application type systems such as those for the .NET Common Language Runtime (CLR) or the Java Virtual Machine (JVM) and XML, with machines doing all of the processing. Invoking a Web Service is achieved by simply sending an XML document to a designated URL endpoint. The Web Service typically responds by sending another XML document back to the client. The combination of a request and response message is typically referred to as a Web Service operation.
Since Web Service operations are machine consumable, it would make sense if their descriptions (or metadata) were also machine consumable. In other words, a machine should be able to query a particular endpoint and discover what services are available and determine how they work.
The Web Service Description Language (WSDL) is an ongoing initiative that's attempting to standardize how Web Services can be described in XML format. Microsoft .NET Beta 2 supports the current WSDL draft for this purpose. A WSDL document describes a service's operations in terms of messages and (typically) XML Schema type definitions, as well as how they are bound to various protocols and endpoints.
Once a client can get its hands on a WSDL document, it should have enough information to know how to interact with the target Web Service. But how does the client get its hands on a WSDL document? If the client knows where the WSDL document resides, it can simply ask for it via HTTP. However, if the client doesn't know where the WSDL lives, a discovery mechanism is needed.
DISCO, introduced in .NET, makes it possible for clients to reflect against endpoints to discover services and their associated WSDL documents. DISCO is supported in the current betas through several helpful tools.
On a larger scale, the standards organizations have been working on the UDDI discovery protocol (see http://www.UDDI.org). UDDI defines an API for interacting with a centralized Web Service information repository. Developers can register their services with a UDDI site, and other developers can query the site to find info. In order to support richer, more specific lookups, a UDDI site holds much more information than simply the WSDL document.
Deploying Web Services
Deployment is the process of copying all of the service's required files to the production machines where it will reside. Deployment of an Internet Information Services (IIS)-based Web Service requires that you create a virtual root (vroot) on the production Web server running IIS and copy the .asmx/.ashx files and other configuration files into that vroot. A \bin subdirectory within the new vroot houses all of the assembly dependencies.
To configure a Web Service, create a web.config file for the particular service and place it in the vroot along with the other files. A web.config file makes it possible to override the vroot's default configuration settings with respect to compilation, security, globalization, and HTTP handler mappings. The directory of a simple Web Service that resides in the math vroot would be structured like the following directory:
Discovery with DISCO
In the past, most consumers found out about new Web Services (and their endpoint addresses) by browsing the Web, receiving an e-mail, or by word-of-mouth. Now, DISCO can define a document format along with an interrogation algorithm, making it possible to discover the Web Services exposed on a given server. DISCO also makes it possible to discover the capabilities of each Web Service (via documentation) and how to interact with it (via WSDL). To publish a deployed Web Service using DISCO, you simply need to create a .disco file and place it in the vroot along with the other service-related configuration files, like so:
The .disco document is an XML document that simply contains links to other resources that describe the Web Service, much like an HTML file that contains human-readable documentation or a WSDL file containing the interface contract. The following is a DISCO document skeleton that will serve as a starting point.
<!-- references go here -->
Notice that the root element has the name discovery from the http://schemas.xmlsoap.org/disco/ namespace. The references to other resources are placed within the discovery element:
<!-- reference to other DISCO document -->
<!-- reference to WSDL and documentation -->
The main element is contractRef, which belongs to a different namespace than the rest of the DISCO-related elements. contractRef has two attributes, ref and docRef, which point to the WSDL and documentation files for a given Web Service.
The discoveryRef element lets you link the given DISCO document to other DISCO documents. This linking allows you to create a Web of related DISCO documents spanning multiple machines and even multiple organizations. This is especially useful if the DISCO client utility provides a mechanism to traverse the links. These are the only elements that you have to be concerned about in the DISCO namespace.
DISCO Client Utilities
There are currently two tools available for discovering the DISCO document once it's in place. One is a command-line client called disco.exe; the other is the Add Web Reference feature in Visual Studio® .NET.
The following command line simply takes the URL of the DISCO document to discover.
c:\temp> disco.exe http://localhost/math/math.disco
This generates an output file (results.discomap) that contains information about the Web Services discovered at the specified URL (see Figure 1). It also downloads all the .disco and .wsdl documents that were discovered.
There is also a command-line utility called wsdl.exe that can generate Web Service proxies from WSDL documents or the .discomap files generated by disco.exe. You can run it like so:
c:> wsdl resuls.discomap
Visual Studio .NET provides a nice user interface for discovering the Web Services available at a given endpoint. In order to use this, go to Project | Add Web Reference and type in the URL to the .disco file that you want to discover (see Figure 2). This command also allows you to add a reference to the selected Web Service to a Visual Studio .NET project. This automatically generates the proxy code (just like wsdl.exe) and adds it to the Visual Studio .NET project within a distinguished namespace.
Figure 2 Adding a Web Reference
Notice that once you've directed the dialog to a .disco file, it displays the raw file in the left pane and provides links to the WSDL document (View Contract) and the documentation file (View Documentation) in the right pane. Those are just links to the contractRef element's ref and docRef attribute values. If the DISCO document contains links to other DISCO documents (through discoveryRef elements), they also show up as links that can be navigated in the right pane.
Figure 3 Viewing the WSDL Document
Clicking on the View Contract link displays the WSDL document referenced in the .disco file, as shown in Figure 3. Clicking the View Documentation link displays the document referenced in the .disco file (typically HTML-based), as shown in Figure 4.
Figure 4 Viewing an HTML Document
Up to this point, all of the examples have required the client to specify the exact address of the .disco file on the server. In most situations prospective clients won't know the exact address of the .disco file, so DISCO also makes it possible to provide hints in the vroot's default page.
If the vroot's default page is an HTML document, you can use the LINK tag to redirect the client to the .disco file:
If the vroot's default page is an XML document, you can use the xml-stylesheet processing instruction to accomplish the same thing:
<?xml-stylesheet type="text/xml" alternate="yes"
With these redirects in place, clients can simply point the discovery tools to the vroot and they will be automatically redirected to the specified .disco file (see Figure 5).
Figure 5 Redirecting
DISCO and Dynamic Discovery
The DISCO discovery process just described relies on static documents and hardcoded references to the supporting resources. But DISCO also provides a dynamic discovery mechanism. To enable dynamic discovery, a .vsdisco file like the one shown here must be placed in the desired vroot.
Notice that the root element is now named dynamicDiscovery and it belongs to a different namespace (urn:schemas-dynamicdiscovery:disco.2000-03-17).
Requests for .vsdisco files are handled by System.Web.Services.Discovery.DiscoveryRequestHandler, which dynamically generates a DISCO document based on the resources found in the target vroot. This document will look just like the static DISCO documents described earlier.
To generate the document, DiscoveryRequestHandler searches recursively through all subdirectories, looking for .asmx and .disco files. All .asmx files that are encountered are added to the DISCO document as a contractRef element. All .disco files found are added to the DISCO document as a discoveryRef element. The resulting document looks just like the static documents that were shown earlier.
For example, consider this Web Service directory layout:
An HTTP request for foo.vsdisco produces the DISCO document that is illustrated in Figure 6.
Figure 6 A DISCO Document
It is possible to specify directories that should be excluded from the discovery process through the exclude element, like so:
<exclude path="_vti_cnf" />
<exclude path="_vti_pvt" />
<exclude path="_vti_log" />
<exclude path="_vti_script" />
<exclude path="_vti_txt" />
<exclude path="Web References" />
The dynamic discovery mechanism is preferred by most developers due to its simplicity, and it is the default mechanism used by Visual Studio .NET Web Service projects. When you create a new .asmx Web Service project, a dynamic discovery document is automatically created. Once again, it's still necessary to provide the proper redirect links to the dynamic .vsdisco file if you want clients to be able to reference the vroot directly instead of referencing the actual file name.
As you can see, DISCO makes it possible to discover Web Services on a given server, but it's somewhat limited in scope and functionality because it doesn't attempt to sort Web Service-related information into categories to enable more sophisticated queries as are possible with UDDI.
UDDI as a Better DISCO
UDDI, which is rapidly evolving as a standard, goes beyond DISCO by defining how to interact with a full-fledged Web Service information repository. The UDDI specification consists of a programmer's API along with an XML Schema definition of supporting data structures and messages.
An operator site implements the UDDI specification and allows users to publish their own Web Service information for increased exposure and query the site for others' Web Service information. Ironically, UDDI is itself a Web Service—all publish and inquiry operations are defined in terms of SOAP messages.
Microsoft and IBM (who, with Ariba, are jointly developing UDDI) both have operating sites up and running today at http://uddi.microsoft.com and http://www-3.ibm.com/services/uddi/, respectively. Although most large operator sites (like those just listed) will allow arbitrary users to publish Web Service information, individual organizations may choose to do their own.
It's difficult to tell at this point whether UDDI will ultimately become centralized or distributed, but recent computing history has shown that a distributed model fosters growth.
What's in a UDDI Repository?
UDDI repositories contain information about businesses, services, and service bindings as well as additional metadata for categorization purposes. The way UDDI organizes this information is similar conceptually to how it's done in a phone book with colored pages. UDDI uses white pages, yellow pages, and green pages the same way that the phone book does.
The white pages include business name, address, and contact information. The yellow pages include categories based on standard taxonomies, and the green pages include the technical specifications and references (see Figure 7). UDDI registries support several types of lookups tailored for a variety of different user groups.
Figure 7 UDDI Pages
A UDDI registry contains four main types of information: businesses, services, binding templates, and tModels. Each business in the registry exposes basic information such as name, address, and contact info, as well as technical information related to its services. Each of the services consists of technical/business descriptions and categorizations. Each service also exposes binding template information that describes how to connect to and communicate with the given service (see Figure 8).
Figure 8 Binding Information
The information provided by services and their binding templates isn't always sufficient to determine compatibility. Simply knowing where to connect and how to communicate is just the first step; you also need to know the interface contract and its associated behavior. A tModel is essentially a technical fingerprint used to describe these things (much like a component category in COM). tModels are used as binding template metadata to help users determine if they're compatible with a given service based on interface, behavior, or some other concept. tModels are just opaque identifiers that are registered with the UDDI site to allow for more precise, application/domain-specific identification.
UDDI Programmer's API
The UDDI Programmer's API is divided into two groups of operations: inquiry and publishing. The inquiry API provides operations for retrieving information from the registry, while the publishing API provides operations for publishing information to the registry.
Figure 9 describes the UDDI inquiry operations. Anyone can use the inquiry APIs without being authenticated by the operator site. The find_XXX operations allow users to perform criteria-based queries for businesses, services, bindings, and tModels. The following code illustrates how to perform a business lookup by the company's name (in this case it's Microsoft).
<?xml version='1.0' encoding='utf-8'?>
<find_business generic="1.0" xmlns="urn:uddi-org:api">
The result of the find_business operation is a list of businessInfo elements that contain information about its services, as shown in Figure 10.
As you can see, invoking the UDDI find_business API is simply a matter of constructing the appropriate SOAP request message and sending it to one of the UDDI site endpoints. The SOAP response message contains the result of the API invocation.
If someone had the business key but didn't know the service key, she could use find_service to search for a service by name, as you can see in the following code:
<?xml version='1.0' encoding='utf-8'?>
<name>UDDI Web Services</name>
The result of the find_service operation is a list of serviceInfo elements containing the service details of those elements that matched the search criteria (see Figure 11).
The get_XXX operations allow users to retrieve the details of a particular business, service, binding, or tModel. Once a service identifier has been obtained (such as after a call to find_business or find_service), you can call get_serviceDetails to retrieve a full report of the specified service's details, as shown here:
<?xml version='1.0' encoding='utf-8'?>
The result of this operation is a businessService element that contains all the information about the specified service (see Figure 12).
Figure 13 describes the UDDI publishing operations. The save_XXX operations allow users to register new information or update existing information. Figure 14 shows how to save new business information to the registry. The delete_XXX operations allow users to remove information from the registry. Since the publishing APIs alter the operator site's registry, user authentication and encryption is required before performing a publishing operation. Users can authenticate themselves through get_authToken operation, specifying a user name and password. The site will return an authentication token that is used in all future publishing operations. Users can then use the discard_authToken operation when they are finished publishing to invalidate the authentication token for future use. For examples showing how to use the publishing API, see the UDDI specification and related whitepapers.
Microsoft provides the UDDI SDK to help simplify writing UDDI client applications against the UDDI programmer's API. The UDDI SDK hides all traces of XML/SOAP by allowing the developer to work with native objects, as shown in Figure 15. The latest version of the UDDI SDK, 1.75, is designed for use in conjunction with the .NET Framework.
One of the main benefits of UDDI's richer data model and more advanced inquiry API is that developers can build their applications around certain types of Web Services, each with the same technical specifications, interfaces, and protocols that can be discovered at runtime (just like COM component categories). This allows applications to automatically take advantage of new and improved Web Services (of that specific type) that are published after the application ships. Building applications with this functionality requires the lookup and categorization features offered today only by UDDI.
However, even though it's technically possible to build discovery-driven applications, most developers won't do it. Developers want to choose their business partners a priori so they can establish strong relationships based on quality assurance and future legal liabilities. No serious developer is going to allow the inclusion of some hacker's completely untested service to debilitate his or her aggregate application.
This is exactly why COM component category-based applications never gained wide acceptance in the industry. And since most of today's UDDI hype revolves around this type of discovery-driven application, it's unclear as to how much better this beefed-up API will be compared to something that is more primitive like DISCO.
If the information in the existing UDDI repositories is a sign of future acceptance, it's not looking good. If you browse some of the test UDDI sites, you'll notice that there is plenty of yellow page information (like business name, business details, and so forth), but very little technical information (such as contract information or WSDL documents).
Developers using DISCO today have found it simple and effective, and they retain complete control over the discovery process. Moving to UDDI increases the complexity by an order of magnitude and forces developers to either relinquish control to a centralized UDDI operating site or implement their own. It's hard to imagine that many will rush to implement that solution.
A Compromise: UDDI-Lite
A compromise between DISCO and UDDI might be the best solution. At a recent XML conference, I discussed this topic with fellow MSDN Magazine columnist Don Box. In response, he hacked out a cool sample that we dubbed UDDI-Lite. The idea behind this sample was to provide a centralized Web Service repository for organizations that would be easy to maintain, and would integrate with all of the existing .NET DISCO-based tools.
To accomplish this, we decided to store the Web Service information in a SQL Server™ database. We provided an ASP.NET front end that developers would use to register and unregister Web Service information—the same information that a developer would put in a .disco document. Any developer in the organization could easily add new entries that would be exposed through a central .disco document (see Figure 16).
Figure 16 UDDI-Lite
Then when clients request the uddilite.vsdisco file in the sample's vroot, it's automatically generated from the information stored in SQL Server. This is accomplished by mapping requests for uddilite.vsdisco to the ASP.NET System.Web.UI.PageHandlerFactory class. This causes the runtime to treat the uddilite.vsdisco file just like a standard ASP.NET page, which is shown in Figure 17.
This sample could easily be extended to support more advanced queries such as one to find all services that support the specified WSDL port type, but it's much simpler than UDDI and it allows organizations to retain control.
Once Web Services have been exposed, it makes sense to publish them through a mechanism that supports machine-driven discovery. DISCO was initially a Microsoft discovery protocol that was never meant for more than simple document-based lookups. DISCO is ultimately limited by the type and depth of the information that it provides. Microsoft has also been heavily involved in the development of UDDI, which is receiving a lot of attention. How successful it will be ultimately remains to be seen. The bottom line is that DISCO works today and it can help you get more mileage out of your .NET Web Services with little effort. For the future, keep your eye on UDDI developments.
Send questions and comments for Aaron to email@example.com.