Universal Description, Discovery, and Integration (UDDI)


DISCO does a good job of allowing Web services on a particular server to be detailed and used, but it has one major problem: you have to know the server that the Web service sits on and, in most cases, also the exact address of the Web service.

To address this shortcoming, Microsoft and IBM teamed up to produce the UDDI specification, which allows Web services to be added to an online “yellow pages” of Web services. The specification has since been passed to OASIS (a not- for-profit, global consortium) and now has the backing of most of the major players in the industry—Sun, VeriSign, SAP, and Compaq, to name just a few.

Note

The UDDI Web site is at http://www.uddi.org, and the OASIS Web site is at http://www.oasis-open.org. The latest release of the UDDI specification can always be found at http://www.uddi.org /specification.html. Although the current release of the specification is version 3.0, version 2.0 of the specification is the latest version to be ratified by OASIS. The Microsoft tools support only up to version 2.0, and the UDDI Enterprise Services in Windows 2003 Server are compliant only up to this version. Therefore, we’ll concentrate on version 2.0 of the specification in this chapter.

UDDI is not a specification for describing Web services. As you’ll see, the actual description of Web services is accomplished using WSDL—UDDI is simply used as a yellow pages of Web services. Within the definition of a Web service in UDDI, you point at the WSDL document that describes the Web service.

UDDI is also not simply a specification. Microsoft, IBM, SAP, and NTT Communications have also implemented what might be described as root UDDI Business Registries (UBRs), which you can use to store the details of the Web services you create.

We’ll go into detail about UDDI in upcoming sections. First you need a basic understanding of how a Web service and its ancillary details are described within UDDI. Figure 4-6 shows the elements that the UDDI specification defines for storing information in the UBRs.

click to expand
Figure 4-6: Overview of the data structures used by UDDI

The entire point of UDDI is to allow access to information about Web services. In UDDI parlance, we’re looking for information about a businessService. The businessService structure represents the service you access (a high-level description of the Web service) and is the structure in UDDI that you’re likely to see most often.

As you can see in Figure 4-6, a businessService is a child of the businessEntity structure. The businessEntity structure represents the publisher of the Web service. A publisher can publish many different Web services. Closely related to the businessEntity structure is the publisherAssertion. A publisherAssertion structure allows the relationship between businessEntity objects to be quantified. For example, the different divisions within a company might be registered as separate businessEntity objects, but can show the relationship among the divisions with a publisherAssertion structure.

The businessService structure on its own doesn’t tell the full story, however. As Figure 4-6 shows, a tModel structure, which is ultimately related to the businessService structure, gives UDDI much of its strength.

You can think of a tModel as the interface of the Web service. It describes the methods that a businessService exposes, as well as the way in which the tModel must be accessed.

A businessService can expose multiple interfaces, and as such it can be related to multiple tModel structures. The relationship between the businessService and the tModel structures is handled via a bindingTemplate structure. The bindingTemplate structure also contains, among other things, the address of the businessService.

The relationships between the structures are constrained using Universally Unique Identifiers (UUIDs). Each instance of a structure has a UUID that identifies that structure. When a structure references another structure, it simply holds a pointer to the UUID of the referenced structure. For example, a businessService object that’s related to a businessEntity object contains a reference to the UUID for the businessEntity object.

The UDDI Business Registries

As mentioned earlier, UDDI is not simply a specification. A rather large specification document details the data structures and the API that UDDI exposes, but without the UBRs, the API is useless.

Four UBRs are currently available (as well as three test registries):

  • http://uddi.microsoft.com (and http://test.uddi.microsoft.com)

  • https://uddi.ibm.com/ubr/registry.html (and https://uddi.ibm.com /testregistry/registry.html)

  • http://uddi.sap.com (and http://udditest.sap.com)

  • http://www.ntt.com/uddi

As you can see from the list, Microsoft, IBM, and SAP all provide test registries as well as live registries. The live registries are used to advertise Web services that are, well, live. You should use the test registries for all development and testing work and move the details across to the live registry only when you go live with the Web service.

All of these UBRs store the information required by the UDDI specification, but they differ slightly in how they allow the information to be interrogated and amended. We’ll concentrate on the Microsoft test UBR, http: //test.uddi.microsoft.com.

Both the live and test UBRs have exactly the same functionality. The only difference is in the URL of the calls to the UBR.

Note

Both of the Microsoft UBRs use Microsoft Passport as the authentication mechanism for accessing the sites. We’ll assume in this chapter that you already have a Passport account.

UBR Concurrency

You might assume that each of the four UBRs contains unique data. This is not the case; the data between the live registries is synchronized on a daily basis. Details entered on the Microsoft UBR will be available on the IBM and SAP UBRs after a day or two.

Although the data is synchronized on all the UBRs, only the UBR that originated the data can modify the data. Only it knows which account the details belong to.

Categorization and Identification

The mainstay of the yellow pages is the categories that contain the entries. We can do a similar thing with UDDI entries by applying categories to businessEntity objects, businessService objects, and tModel objects. We’ll now look briefly at the categorization and identification of Web services; keep in mind that this is far from an exhaustive discussion.

The UDDI Category System

It is perfectly possible to search for a Web service by name, but this is not always practical. If you have a simple Web service that adds two numbers, it might be called AddTwoNumbers, SumNumbers, NumberAdd, or one of other names that you can no doubt think of. It would be better in this case to classify the Web service by category. Adding it to a Mathematics category would be a start, and adding it to an Addition subcategory would be even better. Users looking for the Web service can then narrow their search as appropriate.

We can add categorization data to businessEntity, businessService, and tModel objects. Three taxonomies that have been defined thus far, and they are a core part of UDDI. These are shown in Table 4-1.

Table 4-1: Taxonomies Defined in the UDDI Specification

Taxonomy

tModel Name

North American Industry Classification Scheme (NAICS)

ntis-gov:naics:1997

Universal Standard Products and Services Classification (UNSPSC)

unspsc-org:unspsc

ISO 3166

uddi-org:iso-ch:3166:1999

The first two taxonomies are used to categorize the Web service into functions; ISO 3166 is used to provide geographical categorization. A deprecated version of the UNSPSC category is also defined in the specification; because it is deprecated, it is wise to use the latest version, which is listed in the table.

Each UBR can also define its own category taxonomies. Microsoft has added, among others, the VS Web Service Search Categorization taxonomy, which allows easier searching from within Visual Studio .NET, and microsoft- com:geoweb:2000, a geographical taxonomy.

Note

Categorization helps immensely, but it is not a perfect solution. Not everyone will correctly categorize a Web service in minute detail. Suppose we’re using the UNSPSC taxonomy and I register my Web service in the Janitorial Equipment category, which is a subcategory of Cleaning Equipment And Supplies. Nothing can stop a direct competitor from registering its Web service in the far more general Cleaning Equipment And Supplies category and potentially getting more searches that find its Web service. Someone searching for Janitorial Equipment and someone searching for Cleaning Equipment And Supplies will see a completely different set of results because UDDI does not support the searching of hierarchies within categories.

The UDDI Identifier System

Although you can use the category system to document your Web services, sometimes you’ll want to store data that doesn’t fit into any of the existing categorization schemas. In addition to a category system, UDDI implements an identifier system that allows you to add arbitrary identifiers to businessEntity structures and tModel structures. The UDDI specification defines two identifier taxonomies—Dun & Bradstreet Numbers (see http://www.dnb.com) and Thomas Register Supplier Codes (see http://thomasregister.com). If your business has a Dun & Bradstreet Number or a Thomas Register Supplier Code, you might want to allow your customers to search for your business in this manner.

When you add an identifier, you must select a tModel that the identifier you’re entering belongs to. Each UBR can define its own identifier taxonomies. Also, you can define your own tModel structures for this purpose. The UDDI specification provides two tModel structures that relate to the identifier taxonomies we've already seen, as shown in Table 4-2.

Table 4-2: Identifiers Defined in the UDDI Specification

Identifier

tModel Name

Dun & Bradstreet

dnb-com:D-U-N-S

Thomas Register

thomasregister-com:supplierID

Searching for Web Services

As you’ll see later in the chapter when we cover the UDDI API and the Microsoft SDK, you can access the data stored in a UBR in several ways. For now, we’ll look at using the Microsoft UBR to search for Web services.

The Microsoft UBR allows you to search for available Web services in a number of ways, depending on your requirements. You can navigate to the main search screen by choosing Search from the toolbar of the Microsoft UBR Web page or from the Tools menu on the left of the page. The search page is shown in Figure 4-7.

click to expand
Figure 4-7: Searching the Microsoft UBR

Note

The Microsoft UBR uses slightly different terminology from that used by the UDDI specification and the other UBRs. In the Microsoft UBR, businessEntity structures are called providers and businessService structures are called services. These might make more sense to a user of the UBRs, but as you’ll soon see, the Microsoft SDK uses the names given by the UDDI specification. The terms can be used interchangeably, which is worth bearing in mind when you use UDDI.

As you can see in Figure 4-7, four tabs allow you to query the UBR in different ways. The default option is to specify a categorization scheme, select a category to query, and then search by provider, service, or tModel.

You also have the option of querying the UBR for providers, services, or tModel structures by using one of the other tabs. You can immediately limit your search and be more specific about the item you’re searching for. On the Services tab, for example, you can specify two criteria instead of the one on the Browse By Category tab. As shown in Figure 4-8, you can specify the category or a tModel to limit the search.

click to expand
Figure 4-8: Specifying the query type to further refine a search

Searching for services allows you to specify search criteria based on the category or the tModel; searching for providers or tModels allows you to specify different search criteria. If you search for a tModel, you obviously can’t specify a tModel as a search criterion; you’re limited to specifying categories and identifiers. When you search for providers, you can specify criteria based on categories, identifiers, and tModels.

When you perform a query using the Microsoft UBR, you are presented with a summary of the results in the left pane. You can select one of the results to see its complete details.

Later in the chapter, we’ll implement some Web services and add them to UDDI. If we perform a search for one of these services, NOSBasicServiceA, and then click on its name in the results pane, we’ll see the details of the service, as shown in Figure 4-9.

click to expand
Figure 4-9: Viewing service details

As you can see, we’ve obtained the full details of the service. However, if you look at the Explorer tab of the left pane, you’ll see that we’ve also obtained the provider for the service (NotAShop.com) and a sibling service (NOSBasicServiceB). The Explorer tab allows you to navigate the results that are returned.

The UDDI API

We mentioned that you can query the data stored in the UBRs using the UDDI API. In this section, we’ll briefly talk about how to do this. What we won’t do is use the UDDI API to access the UBRs. Not only would this be extremely tedious, but better tools are available for querying the UBRs programmatically. Here we’ll simply give a high-level overview of the UDDI API so you can get an idea of what is possible. The Microsoft UDDI SDK is an excellent wrapper for the complexities of the UDDI API and is the preferred method for programmatically accessing the data stored in the UBRs.

The UDDI API has two parts, the Inquiry API and the Publishing API. The Inquiry API provides all the searching functionality of the UBRs, and the Publishing API provides all of the details about the management of the information within the UBRs.

The Inquiry API

The Inquiry API, which contains methods for interrogating the UBRs, supports two methods of searching—one traditional method and one in which you specify exactly what you require using a UUID. These methods are differentiated by the find_ and get_ prefixes, respectively.

The methods with a find_ prefix, shown in Table 4-3, are used to query the UBR based on search criteria.

Table 4-3: The find_ Inquiry API Methods

API Method

Description

find_binding

Returns a bindingTemplate message with details for a given service UUID and tModel UUID.

find_business

Returns the list of businessEntity UUIDs that meet the optional search criteria (name, tModel, categories, and identifiers).

find_relatedBusinesses

Returns a list of businessEntity UUIDs of businesses that are related to the given business UUID.

find_service

Returns a list of businessService UUIDs that meet the search criteria (name, tModel, and categories). You can also limit this search to a given businessEntity.

find_tModel

Returns a list of tModel UUIDs that meet the search criteria (name, categories, and identifiers).

Each of these methods, with the exception of the find_binding method, returns a list of UUIDs. The find_binding method is different because it is the lowest-level method you can use. Rather than returning a list of UUIDs that meet the search criteria, find_binding returns details of a specific bindingTemplate.

Table 4-4 lists the get_ methods, which return details of a given item when you know its UUID.

Table 4-4: The get_ Inquiry API Methods

API Method

Description

get_bindingDetail

Returns bindingTemplate details for a given bindingTemplate UUID.

get_businessDetail

Returns businessEntity details for a given businessEntity UUID.

get_businessDetailExt

Functionally equivalent to the get_businessDetail method. This method is meant to be extended for nonroot UBRs and allows extra data to be returned.

get_serviceDetail

Returns businessService details for a given businessService UUID.

get_tModelDetail

Returns tModel details for a given tModel UUID.

The Publishing API

The Publishing API allows you to modify the data within a UBR and is considerably more complex than the Inquiry API.

The first group of methods we need to look at are the methods that control access to the UBR, as described in Table 4-5. Before you can use any of the methods available in the Publishing API, you must retrieve an authentication token from the UBR that can be passed whenever you make a call to a Publishing API method.

Table 4-5: Publishing API Authentication Methods

API Method

Description

discard_authToken

Releases the authentication token specified in the call.

get_authToken

Requests an authentication token using the details provided.

get_registeredInfo

Returns the complete businessEntity and tModel data stored in the UBR for the authenticated user.

The second group of methods are for modifying the data in the UBR. This group includes methods to delete objects from the UBR and methods to save objects to the UBR, as described in Table 4-6.

Table 4-6: Publishing API Data Modification Methods

API Method

Description

delete_binding

Deletes the bindingTemplate specified by the given bindingTemplate UUID.

delete_business

Deletes the businessEntity specified by the given businessEntity UUID.

delete_service

Deletes the businessService specified by the given businessService UUID.

delete_tModel

Deletes the tModel specified by the given tModel UUID.

save_binding

Saves the bindingTemplate specified to the UBR.

save_business

Saves the businessEntity specified to the UBR.

save_service

Saves the businessService specified to the UBR.

save_tModel

Saves the tModel specified to the UBR.

The delete_ methods take a UUID and simply delete the object in question. The save_ methods are used in two situations. If you want to modify an object in the UBR, you call the save_ method with the UUID specified; the data in the UBR will be overwritten with the new data that you pass as part of the method. To add a new object to the UBR, you call the save_ method without a UUID specified, and a new entry will be created within the UBR.

When you attempt to modify an item in the UBR, a check is made to ensure that the details you provided when you were authenticated allow you to perform that action. You can delete only items that you created, and you can save an item only if you created the item’s parent. (For example, you can’t save a businessService to a businessEntity that you didn’t create.)

The final group of methods, described in Table 4-7, deal with relationships.

Table 4-7: Publishing API Data Modification Methods

API Method

Description

add_publisherAssertions

Allows publisherAssertion information to be added.

delete_publisherAssertions

Deletes existing publisherAssertion information.

get_assertionStatusReport

Returns the status of the publisherAssertions for the authenticated user.

get_publisherAssertions

Returns the complete set of publisherAssertions for the authenticated user.

set_publisherAssertions

Replaces the publisherAssertions with those specified in the call.

The UDDI SDK

As we mentioned, the Microsoft UDDI SDK provides a wrapper around the methods that are available in the UDDI API. Every method in the API has a corresponding class with a Send method that allows you to query and modify the details in a UBR. You simply populate the necessary properties of the class that you instantiated and call the Send method to make the call to the specified UBR.

Note

The latest version of the UDDI SDK for .NET is part of the February 2003 Platform SDK, which can be downloaded from http://www.microsoft.com/msdownload/platformsdk/sdkupdate/update.htm. You need to download the Windows Server 2003 Core SDK. To correctly install the UDDI SDK, follow the instructions in the uddireadme.htm file contained in the bin directory.

It would take an awfully long time to walk through every property and method of every class that is available in the UDDI SDK. Because of the similarities in how the underlying data is structured, the same methodology is applied to the four groups of methods (find_, get_, save_ and delete_). We won’t look at the portions of the UDDI SDK that deal with the relationships between providers, but once you have an understanding of the way the rest of the UDDI SDK works, you can quickly learn to use those portions.

Connecting to the UBR

The UDDI SDK controls access to a UBR through the use of a UddiConnection object. In addition to allowing you to specify which UBR you want to use this, class also wraps the implementation of the UDDI API authentication classes.

As you saw in Table 4-5, three methods in the UDDI API deal with authentication. Using these methods to retrieve authentication information is tricky; thankfully, the UDDI SDK handles all of the details of retrieving the AuthInfo token from the UBR and attaching it to requests to the Publishing API, as you’ll soon see.

To connect to the UBR, you simply create a new UddiConnection object and pass in the necessary details to the constructor. The UddiConnection class provides seven constructors, but in most cases you’ll deal with only two of them.

If you want only to query the UBR, you can create the UddiConnection object and simply pass in the URL of the Inquire API that you want to access. This will create a connection object that can query the UBR but nothing more. You’ll see this type of connection in use in the Query application, which we’ll build shortly.

If you want to publish to the UBR, you must create the UddiConnection object and pass it a few more details. In addition to passing the URL of the Inquire API, you must also pass the URL of the Publishing API and the username and password that you want to use as the authentication details. In our second application, the Browser application, you’ll see this type of connection in use; this application allows you to modify the information contained in the UBR.

As you’ll see shortly, all the classes that interact with the UBR have a Send method. You must pass a valid UddiConnection object to this method for the call to the UBR to be made.

When you’re finished with a UddiConnection object, you can close the connection using the Close method.

The Find Classes

The first methods we’ll look at are the find_ methods: find_binding, find_business, find_service, and find_tModel. As you saw in Table 4-3, these methods allow you to set various search criteria and then query the data in the UBR. The four API methods are wrapped by classes with names that start with Find. These classes expose properties (such as the Names property and the CategoryBag property) that allow you to set the search criteria before you call the Send method to interrogate the UBR.

For three of the classes—FindBusiness, FindService, and FindTModel—the Send method interrogates the UBR and returns an object of the corresponding class: BusinessList, ServiceList, or TModelList. The fourth class, FindBinding, doesn’t return a list of bindings; it returns the details of a specific binding, BindingDetail, which we’ll look at shortly when we deal with the Get classes.

The three lists—BusinessList, ServiceList, and TModelList—each contain a collection of objects that represent the individual items returned. The BusinessList class exposes a collection of BusinessInfo objects through the BusinessInfos property; the ServiceList class has a ServiceInfos property, which is a collection of ServiceInfo classes; and the TModelList class exposes a collection of TModelInfo classes via the TModelInfos property. The BusinessInfo, ServiceInfo, and TModelInfo classes each expose properties for the object’s UUID and for its name.

The BusinessInfo class also contains the ServiceInfos collection, which contains a ServiceInfo class for each of the services that the business owns.

When you have a list of items, you still don’t have any real information about the item—just the names of the items and their UUID. You must use the Get classes to obtain the full details.

The Get Classes

You use the Find classes to search the UBR; you use the Get classes to return complete details about one or more items within the UBR. Like the Find classes, the get_ API methods are wrapped in a class of the same name. They each require a collection of UUIDs to be specified and return the full details for the given UUIDs.

Each call to the Send method of a Get class returns an object that contains the collection of items requested. GetBusinessDetail returns an object of class BusinessDetail, GetServiceDetail returns a ServiceDetail object, GetBindingDetail returns a BindingDetail object, and GetTModelDetail returns a TModelDetail object.

Unfortunately, the common name scheme that we’ve followed thus far breaks down when we look at the collections of objects that these detail classes expose. The BusinessDetail class exposes the BusinessEntities property, which is a collection of BusinessEntity objects. The ServiceDetail class has the BusinessServices property, which is a collection of BusinessService objects. The BindingDetail class exposes the BindingTemplates property. And the TModelDetail class has the TModels property.

As you know, the data stored in the UBR is hierarchical—a binding is related to a service, which is related to a business. The information returned by the Get classes maintains this relationship. Each BusinessEntity object that the Get classes return contains a BusinessServices property that exposes a collection of all the services that the business owns. The BusinessService class, in turn, has a BindingTemplates property, which exposes a collection that contains all of the bindings for the service.

The Save Classes

The four save_ methods of the API allow you to both add and update information in the UBR, and the wrapper classes follow the naming scheme that we’ve come to expect—SaveBusiness, SaveService, SaveBinding, and SaveTModel. To save an item in the UBR, you must create a collection of the correct type and then add this collection to the appropriate Save class before calling the Send method.

Not surprisingly, the collections you must create are the same as the collections that the Get classes return. To save a service to the UBR, you create a BusinessService object representing the service and add the object to the BusinessServices collection of the SaveService class.

Forcing the use of the same collections for the Get and Save classes allows modifications to the UBR to be made easily, by reusing the collections that are returned. You can query for the item you want, modify the returned collection, and save the collection back to the UBR.

One point to consider is the difference between adding data to the UBR and modifying data that is already in the UBR. You perform either action in the same way—the only difference is in the data that you pass to the appropriate Save class. If you’re adding an item to the UBR, the item will not have a UUID; if you’re modifying an item, it will.

The Delete Classes

The five delete API methods are wrapped within five Delete classes (DeleteBinding, DeleteBusiness, and so on) and require you to specify the UUIDs of the items you want to delete. As with the Get classes, you can specify as many UUIDs as you require, and they will all be deleted in the same call to the UBR.

Using the UDDI SDK

The possibilities for what you can do with UDDI and the SDK are vast, and in many cases can simplify processes that you already have in place. We’ll introduce the SDK by building two applications.

The first application uses the SDK to query the Microsoft UBR for Web services that fit a particular tModel. This scenario allows us to call Web services at run time without any prior knowledge of them. Any new services that reference our tModel will be available to us whenever we run the application.

The second application is a simple UDDI browser that allows us to search and modify the information we’ve entered into the UBR. This is a substantially more complex application and introduces the concept of modifying data contained in the UBR.

The sample code for this chapter includes both of these applications.

The Query Application

Imagine a company with several offices around the world that has grown sporadically through planned growth and mergers. Because of the way the company has grown, the information technology systems at the different locations are not the same. However, the company needs to be able to produce management reports that are consistent across the company.

Using UDDI and the tModel concept, we can allow the developers at the various branch offices to build their own proprietary solutions against an interface that is easily propagated. We can publish our tModel and then inform the branch offices that it is available. The branch offices can then develop their solutions and register them as Web services in the UBR.

When we run the monthly reports, we can query the UBR for any services that implement the correct tModel. This query will return a list of services that we can call to generate the report. When new branch offices come online, no changes will need to be made to the head office application because the new Web service will be returned automatically by UDDI.

Note

Our example uses the Microsoft test UBR at http://test.uddi. microsoft.com to share the tModels and the details of the available services. In the real world, we wouldn’t want to use a public UBR because it would make the details available to the world at large. Furthermore, if we were building services on an intranet, we wouldn’t be able to use the public UBRs. The solution to the problem of building UBRs for the intranet is UDDI Enterprise Services, which is available in Windows Server 2003. We’re using the public UBR here so we can show the facilities available without requiring a server that’s running Windows Server 2003.

Building the Web Services

We’ve presented a real-world situation in which you would want to use the UDDI SDK to query a UDDI registry for Web services that meet your requirements, but we won’t actually build any Web services that are this complex. For the purposes of this example, we’ll simply use Web services that implement a simple interface. We have three methods—GetDate, GetURL, and Echo—that return strings to the user; the first two return the information that their name implies, and the third returns whatever string has been passed to it, with a prefix added.

Because we’re dealing with the possibility of accessing multiple Web services at run time, we’ll build two Web services with the same methods. We could simply write the code for these two Web services from scratch, with the interface that we require; doing so would no doubt provide us with two Web services that meet our requirements. However, we can greatly improve on this method by providing an interface, or more correctly a tModel, that can be used as the basis for the Web services that we’re going to build.

The two services we’re going to build are called NOSBasicServiceA and NOSBasicServiceB. They can be found at http://www.notashop.com/wscr/04 /servicea.asmx and http://www.notashop.com/wscr/04/serviceb.asmx, respectively.

Note

Because the tModel we’re using is available on the Microsoft UBR (in a test version), it is available to anyone. Feel free to build on this example and register your own Web services that relate to this tModel. As long as the Web services exist on a Web server that is available on the Internet, they will be available when you query the UBR using our sample application.

Creating a tModel from a Web service

When you build multiple Web services that expose the same interface, you build one version of the Web service as the master. The Web service you select as the master is usually the one you’ve worked with the most, throughout the entire design process. Once the service has been tested and meets your design criteria, you can use it to define the tModel structure for all of the other Web services you plan to implement.

Thanks to the tools provided by the .NET Framework, viewing the WSDL that is generated for a Web service is easy. You simply specify the ?wsdl query string when we view the Web service in a browser. We could use this dynamically generated WSDL file as the tModel, but this approach isn’t advisable—any changes to the Web service will result in the WSDL changing. Any services that are built after the change will no longer meet the requirements that we originally defined. To that end, we’ll create a static WSDL file that we can use for the tModel. We’re less likely to change this WSDL file accidentally, and it gives us a means of fixing the interface for our tModel.

To create the tModel for this service, however, we will start with a dynamically generated WSDL file. If we view the WSDL file, we can save it and use it as the basis for our tModel. We can then modify the file to meet the necessary criteria for a tModel definition in UDDI.

To create a tModel from the WSDL for a real Web service, we must first remove the <wsdl:service> element. We now have a correct WSDL document that can be used as a tModel.

Note

As they stand, neither the WSDL specification nor the UDDI specification explicitly defines how the two specifications should interact. This task is left to a UDDI.org best-practice document titled “Using WSDL in a UDDI Registry” (available at http://www.oasis-open.org /committees/uddi-spec/bps.shtml). The crux of this document concerns the definition of tModels that use WSDL, and it describes what is required in the tModel definition. Thankfully, the WSDL required for a tModel is the same WSDL that you’d expect for a Web service, minus the <wsdl:service> element.

We could stop here and use the WSDL document that we now have as our tModel, but normally we further modify the WSDL for the tModel so it is not specific to the master Web service. The item we must change is the <wsdl:binding> element; this is the name used when we generate the proxy classes, and the default ServiceASoap name is specific to the Web service that we used to create the initial WSDL document. In this case, we’ve replaced ServiceASoap with NOSBasic; the WSDL for the tModel can be found at http://www.notashop.com/wscr /04/nosbasic.wsdl.

Generating a Web service from a tModel

Now that we have a tModel, we’ll use it to build the rest of the Web services in this example. We know the full URL for the tModel, so we don’t have to use a UBR to find details about the tModel.

To build a Web service according to a tModel definition, we can use wsdl.exe, the tool we used in Chapter 1 to create proxies to existing Web services. One of the parameters to wsdl.exe is the /server switch, which makes the tool generate an abstract class rather than a proxy. (As you saw in Chapter 1, we can also control the language that the class is generated in as well as a whole host of other parameters.)

To build the abstract class for the tModel that we registered earlier in the chapter, we execute the following command line:

wsdl.exe /server http://www.notashop.com/wscr/04/nosbasic.wsdl

This creates a C# file called output.cs in the current directory that contains an abstract class called NOSBasic. If we add this class to our project, we can inherit from it as we would any other class. We don’t even need to worry about any WebService or WebMethod attributes because they’re all already part of the base class.

Although the subsequent service, serviceb.asmx, was created from this abstract class, we’ve also modified servicea.asmx, the service we used to create the abstract class, so that it, too, inherits from the abstract class.

Note

Be sure to apply the correct namespace for the WebService attribute to your derived classes. Even though we have a namespace specified in the tModel WSDL file, it is not used when we generate an abstract class. If we don’t specify this namespace correctly, we cannot make calls to the Web services because the SOAPAction header will be incorrect and will be rejected automatically by .NET.

Managing Web Services

So far we’ve created three Web services with a consistent interface. We mentioned that we used a tModel when creating the classes, but we haven’t yet used any of the UDDI facilities available.

We’ll start by using the test UBR at http://test.uddi.microsoft.com to register the interface that we defined at http://www.notashop.com/wscr/04 /nosbasic.wsdl as a tModel. We can then register the Web services we’ve built and relate them to the correct tModel. This procedure allows us to search for Web services based on the tModel and search for new Web services at run time.

Until now, we’ve used the UBR without actually logging in. Earlier, when we searched in the Microsoft UBR, the Passport Sign In option was present, indicating that we were not logged in. Before we can actually manage our services, we must log in to Passport and then register with the UBR.

Once we’ve logged in using a valid Passport account, we must also create an account in the Microsoft UBR. This is easy; all we need to provide is an e-mail address (which can be the Passport address we’re using) and, at a minimum, our name and phone number. Clicking Save takes us to the Terms And Conditions page. Accepting the conditions causes the UBR to send us an activation e-mail. Within the activation e-mail is a link that we must click to activate our account within the UBR. Once we’ve activated our account, we’re free to publish to the Microsoft UBR.

The main page when we’re publishing in the UBR is a standard two-pane Web page, with the left pane showing a tree view that has a My UDDI entry— the parent for everything we’ll add to our account. The My UDDI entry currently has empty Providers and tModels folders.

We’ll now walk through the steps for adding the details to allow our service to be used by other developers.

Providers

As you’ll recall from Figure 4-6, the businessEntity (or in Microsoft parlance, the provider) is the root of the data that we store in the UBR. Before we can add any tModels or services, we must enter the details for a provider in the UBR. Within the UBR, we’re normally allowed only one provider per login, but it’s possible to have more providers per login by contacting Microsoft directly.

To add a provider, click on the Providers folder and click the Add Provider button in the right pane or choose Add from the shortcut menu for the folder.

Note

Throughout the Microsoft UBR, a shortcut menu is available in the left pane that performs the same operations as the buttons in the right pane. For clarity, we’ll refer only to the buttons in the right pane.

When we click Add, the Microsoft UBR adds a provider with default values. The name, <New Provider Name>, is not particularly helpful. We can click the Edit button to change the name; as you can see in Figure 4-10, we’ve specified a much more meaningful name.

click to expand
Figure 4-10: A provider added to the Microsoft UBR

The Add Description and Add Name buttons on the page allow us to add a description and another name. If you’re wondering what’s the point of adding a second name to the provider, you should look closely at the English text above the provider name in Figure 4-10. UDDI is language neutral, but it defaults to U.S. English when you add new entries.

The page also has a series of tabs along the top that allow you to add lots of other information about the provider. We’ll cover the Services tab shortly (after we’ve added the tModel details); the other five tabs allow you to add ancillary details to the provider entry:

  • Contacts For adding contacts to providers with full addressing details (both online and offline) as well as the person’s role, as shown in Figure 4-11.

  • Identifiers For adding free-form data to the provider.

  • Categories For placing the provider into any of the categorization schemes we’ve previously discussed.

  • Discovery URLs For adding further technical details for the provider as separate documents. We automatically have an entry to the provider details at the Microsoft UBR that we can’t modify, but we can add further details if required.

  • Relationships For adding details about any relationships that apply to this provider and to authorize relationships that have been requested with this provider.

    click to expand
    Figure 4-11: A contact added to a provider

tModels

Although we can add services to the UBR without any reference to a tModel, we don’t want to do this in our scenario. We’re relying on the services referencing the tModel, so we’ll add the tModel before we add the service.

Adding a tModel is similar to adding a provider. You click on the tModels folder and click the Add tModel button. Once the tModel has been added and its name has been changed to the more meaningful NOSBasic, it appears in the My UDDI tree, as shown in Figure 4-12.

click to expand
Figure 4-12: A tModel added

Unlike the provider, however, a tModel can have only one name that is language neutral. We can add multiple descriptions to the tModel, and these can have a culture specified. (The default is en-US.) As with the provider, we can also add identifiers and categories, which perform the same functions as with the provider.

The point of interest for a tModel is the Overview Document tab. On this tab, we can add the WSDL details for the document by clicking Edit and adding the full URL to the WSDL for the Web service. Figure 4-13 shows the tab after we’ve added the full URL for the Web service.

click to expand
Figure 4-13: A WSDL document added to the tModel

As you can see in the figure, we can also add a description to the overview document and specify the language for this description (which is in the en-US culture by default).

Services

Now that we have a provider and a tModel added to the UBR, we can add our Web service and correctly relate it to the tModel. This procedure, again, is as simple as navigating to the provider we added earlier and clicking on the Services tab. We can then click the Add Service button to add the new service, and once we’ve changed the default name, <New Service Name>, to a more sensible name, we’ll see the Web service added as a child of the provider, as shown in Figure 4-14.

As with the provider, we can add multiple names and descriptions in different languages, the only proviso being that we must have at least one name.

The Categories tab behaves in the same way as for providers and tModels; the Bindings tab allows us to give the service we’ve added a presence in the real world by giving it an address.

On the Bindings tab, we can click the Add Binding button to add a binding as a child of the service in the left pane, and we can add the URL of the Web service as the access point, as shown in Figure 4-15.

click to expand
Figure 4-14: A service added to the provider

click to expand
Figure 4-15: An access point added to the service

Again, we can add multiple descriptions in different languages to the binding we just added.

Although we have a fully working Web service that we can use as is, we still haven’t associated it with a tModel, so we still can’t use it in our application. We can associate a binding with a tModel by clicking the Instance Info tab and entering the name of the tModel that we want to reference, as shown in Figure 4-16.

click to expand
Figure 4-16: Searching for a tModel to add to a service

Once we specify the tModel, the UDDI site adds it to the left pane as a child of the binding, as shown in Figure 4-17.

As with everything else we’ve added, we can add multiple descriptions to the tModel reference and also add any parameters that are required and an overview document that we can use to store more information.

Category Information

Although we’ve stayed away from adding categories to objects that we’ve created within the UBR, we pointed out that it is possible to add categories to providers, tModels, and services. For the service, we’ve added two categories—one that puts the Web service in England (using the ISO 3166 categorization schema) and one that adds us to the Internet Business Services category (in the SIC categorization schema). If we click on the Categories tab for the service, we’ll see the categories for the service listed, as shown in Figure 4-18.

click to expand
Figure 4-17: Category details added to a service

click to expand
Figure 4-18: A tModel added to a service binding

The Client

After all that pointing and clicking, we’re in a position to actually use the UDDI SDK to access the details in the UBR. Included with this book’s sample files is a simply Query application that allows us to query the UBR for Web services that relate to our tModel.

We won’t go through all of the code for the application. A lot of it doesn’t deal with UDDI, anyway—we’ll just discuss the code that is directly related to accessing the UDDI SDK.

Searching for Web services

The first thing we need to do is search for the Web services that implement our tModel. As you’ll recall, all the entities we add to the UBR are referenced using UUIDs. Figure 4-12 showed that when we added the tModel to the UBR, a UUID was automatically generated. To find Web services that implement this tModel, we can use this UUID, 3d544d6c- 4a3a-433f-9b2c-c855f8ffeed8, as the search criterion.

Before we use the SDK, we must add a reference to the correct assembly, Microsoft.Uddi, to our project. We must also add references to the namespaces within the SDK that we’re using. In this case, we need to add the base namespace, Microsoft.Uddi, as well as one of its child namespaces, Microsoft.Uddi.Services:

using Microsoft.Uddi; using Microsoft.Uddi.Services;

Now that we’ve created the necessary references, we can start writing code to access the UBR. The first thing we need to do is create the UddiConnection object that we’ll use, specifying the URL that we’re calling—in this case, the Inquire API of the test UBR. The results are added to a list box control, so we’ll also clear that before we start querying the UBR:

// Create the connection to the UBR UddiConnection m_Connection = new     UddiConnection("http://test.uddi.microsoft.com/inquire");                   // Clear the listbox lstResults.Items.Clear();

From Table 4-3 you’ll recall that the find_service method allows us to specify the tModels we want to search for. We create an instance of the FindService class and add the tModel details to the TModelBag collection before calling the Send method:

// Create the find object and set the tModel we want to find FindService findService = new FindService(); findService.TModelBag.Add("uuid:3d544d6c-4a3a-433f-9b2c-c855f8ffeed8"); // Make the call and return a ServiceList ServiceList serviceList = findService.Send(m_Connection);

The Send method returns a collection of ServiceInfo entities. We can simply iterate through this collection, extracting the information we need. We’ll use the first entry in the Names collection of the ServiceInfo class to retrieve the name of the service. We’ll call this service, so we need to know its UUID to find its address; we can use the ServiceKey property for this purpose:

// Iterate through the returned collection foreach (ServiceInfo serviceInfo in serviceList.ServiceInfos) {     lstResults.Items.Add(serviceInfo.Names[0] + " - "         + serviceInfo.ServiceKey); }

This code populates the list box control with the list of Web services that relate to the tModel we specified, as shown in Figure 4-19. As you can see, not only do we have the name of the service, but we also have its UUID.

click to expand
Figure 4-19: Web services that match the tModel

The list box responds to double-click events, and double-clicking on a Web service launches a dialog box that calls the service.

Calling the Web service

Calling a Web service is a little trickier than simply querying for the details of the service. We search for the details necessary to call the service in a way that is similar to how we get the list of services. However, we must perform a little more work first.

When we call a Web service, we need a proxy class so we can call methods on that class to execute the methods on the Web service. However, we’re discovering Web services dynamically. We don’t have the luxury of being able to create a proxy class because we don’t know the location of the Web service at design time.

The way to overcome this problem is to create a Web reference to the tModel that we based our Web service on, http://www.notashop.com/wscr/04 /nosbasic.wsdl. This file has the complete structure of the Web service and allows a proxy class to be generated. What is missing from this .wsdl file is the address of the service; if we try to call the proxy generated from the tModel, we’ll receive an error telling us that no address to call has been set. We must set this address before we call any methods on the proxy. Confused? All will become clear shortly.

As with any call to the UDDI SDK, we must reference the correct namespaces. We must also reference the proxy we generated from the tModel:

using Microsoft.Uddi; using Microsoft.Uddi.Services; using com.notashop.www;

Again, we set the URL of the UBR that we’re calling. We also create a proxy class so we can call it when required:

// Create the connection to the UBR UddiConnection m_Connection = new     UddiConnection("http://test.uddi.microsoft.com/inquire"); // Create the proxy that we're going to use NOSBasic proxy = new NOSBasic();

Before we can call the service, we must know its address; we need to tell the proxy where to call. You’ll recall that the address of the service is contained as a child of a binding to the service. We must retrieve the details of the relevant binding before we can access the address of the service.

Because we don’t actually have the UUID that will allow us direct access to the binding details, we must use the details we know to obtain the correct binding. We know the UUIDs for both the service and tModel, so we can specify these when we make a call to the UBR using the FindBinding class. As you’ll see, the process for querying for bindings is the same as the process for querying for services.

Note that when we search for bindings we don’t return a list of bindings that meet our criteria—we return a specific binding, a BindingDetail object. We must provide enough information when we make a call to allow us to find an individual binding. If we don’t, the UBR will throw an exception.

// Use the service key to get the binding detail FindBinding findBinding = new FindBinding(); findBinding.ServiceKey = m_key; findBinding.TModelKeys.Add("uuid:3d544d6c-4a3a-433f-9b2c-c855f8ffeed8"); // Make the call and return a BindingDetail BindingDetail bindingDetail = findBinding.Send(m_Connection); 

Now that we’ve retrieved the binding from the server, it should be a simple matter to retrieve the URL of the service. When we added the details of the service to the UBR, we added the URL with the binding and then simply added pointers to the tModels. The UDDI SDK doesn’t follow this pattern, however. The URL of the service is within the pointer to the tModel rather than the binding. This deviation isn’t a big deal—just something to be aware of.

We can have multiple tModels related to this binding, but the URL will be the same across all of them, so we can simply pick one of them at random. The only one we’re sure will be present is the first item in the collection—we can only return results that have a reference to our tModel, so we know for sure that we have at least one reference.

The BindingDetail object that we’ve returned contains a BindingTemplates collection that contains the references to the tModels. We use the first item in this collection and retrieve the Text property of its AccessPoint object, which is the URL of the service. We use this value to set the title of the form as well as the URL of the proxy:

// Set the details correctly this.Text = bindingDetail.BindingTemplates[0].AccessPoint.Text; proxy.Url = bindingDetail.BindingTemplates[0].AccessPoint.Text;

Once the proxy has a URL, we can call the methods on that proxy, safe in the knowledge that the call will be made to the correct location. As you’ll recall, the Web services expose three methods. We call these and place the returned strings into text box controls in the dialog box:

// Call the remote service txtDate.Text = proxy.GetDate(); txtUrl.Text = proxy.GetUrl(); txtEcho.Text = proxy.Echo(Environment.MachineName);

If we select NOSBasicServiceA from the list of services retrieved, we’ll see that a call has been made to the Web service and the results are displayed in the dialog box, as shown in Figure 4-20.

click to expand
Figure 4-20: The results from a dynamically referenced Web service

The UDDI Browser

We’ll now move on to a much more exciting application to show off the power of the UDDI SDK. We’ll build a UDDI browser that allows us to add Web services to the Microsoft UBR.

The UDDI browser will allow us to add services as well as details of the tModels that those services are related to. The application is not designed as a replacement for using the UBRs, and it doesn’t implement the complete UDDI feature list. It’s intended only as an introduction to the more complex features of the UDDI SDK. As we mentioned earlier, trying to completely describe every feature of the UDDI SDK would require an awfully large chapter. For reasons of clarity, we’ll present only the code that is directly related to our interaction with the UDDI SDK. Of course, nothing can stop you from writing a complete UBR replacement, if you want.

The Helper Class

Rather than have code that interacts with the UBR littered throughout the application, as we did in the Query application, we’ll place all the code that interacts with the UBR in a Helper class, contained in the helper.cs file. This class contains static methods that we can call to interact with the UBR. For instance, we have a GetService method that accepts the UUID for a service and returns a BusinessService object representing the requested service and a DeleteService method that accepts the UUID for a service and deletes the service from the UBR.

Rather than detail all of the methods that the Helper class exposes, we’ll look at the methods as we walk through the Browser application.

Connecting to the UBR and Logging In

On launching the application, the first thing we have to do is to log in to the UBR that we’re using. In fact, the Browser application is designed so that if we don’t provide correct authentication details, execution of the application will halt.

Connecting to the UBR to use both the Inquire API and Publishing API is not much more complex than simply connecting to the Inquire API. We simply need to create an instance of the UddiConnection object and specify the correct details.

Within the Helper class is a Connect method that accepts a username and password and creates the correct UddiConnection object, which it then stores as the m_Connection static variable. The complete code for this method is shown here:

internal static void Connect (string strUsername, string strPassword) {     // Connect to the server     m_Connection = new UddiConnection(         "http://test.uddi.microsoft.com/inquire",         "https://test.uddi.microsoft.com/publish",         "",         strUsername,         strPassword); }

Even though we created the UddiConnection and passed in a username and password, these are not validated with the UBR at this time. Only when we make a call to the Publishing API will the details be validated.

Whenever we make a call to a method of the Publishing API, we must attach an AuthInfo token to the method call. As we pointed out, the UDDI SDK takes care of retrieving the AuthInfo token and adding it to the request to the Publishing API.

On the first call to the Publishing API, the UDDI SDK first makes a call to the get_AuthToken method to retrieve the AuthInfo token. The token is cached and added to all future requests to the Publishing API.

Note

If you don’t want the AuthInfo token to be automatically retrieved and added to requests to the Publishing API, you can set the AutoGetAuthToken property of the UddiConnection object to false. This approach requires an AuthInfo token to be populated manually and added to the AuthInfo property of the class that we’re using.

Editing Business Details

The first thing we need to do when we log in to the UBR is retrieve a list of items that the user has permission to modify. When we looked at searching using the UDDI SDK in the previous example, we found that we can use API methods to search for specific items, such as businesses. However, we can’t use these methods now because all we know is the user who is logged into the UBR, and the API has no facility for searching by the owner of an item.

The API provides a solution to this problem—the get_registeredInfo method, which returns a list of the businesses and tModels that the user has permission to modify. As with the other API calls, this method is wrapped in its own class, GetRegisteredInfo, and this is wrapped in the GetForUser method of the Helper class.

internal static BusinessInfo GetForUser() {     // Create the GetRegisteredInfo class     GetRegisteredInfo getRegisteredInfo = new GetRegisteredInfo();     // Make the call     return(getRegisteredInfo.Send(m_Connection).BusinessInfos[0]); }

We don’t need to set any properties of this class because the method requires only a valid AuthToken to be added, and the UDDI SDK handles this automatically.

The business details returned from the call to the UBR are a collection of BusinessInfo objects. Although the UDDI specification allows more than one provider per user, the specification requires only one provider per user. The Microsoft UBRs allow only one provider to be managed, so we simply return the first item in the collection. The business details returned are then used to populate the main form, as shown in Figure 4-21.

click to expand
Figure 4-21: Editing the business details

We populate the main form of the application by first making a call to the Helper.GetForUser static method. This call returns a BusinessInfo object that we store in the l_Business local variable:

// Return the details for the user BusinessInfo l_Business = Helper.GetForUser();

After checking to be sure that we have obtained a BusinessInfo object, we use the cached local variable to populate the details on the form. The Names collection contains the names for the business and, because the business must always have at least one name, we extract only the first name from the collection. The business has only one UUID, and we can extract it from the BusinessKey property. As you’ll recall, the description of the service can be added in multiple languages, and all of the descriptions for the business are returned in the Descriptions collection. The description of a service is not mandatory, so we check that we have a description before attempting to populate the form with the first description in the collection:

// Populate the form txtName.Text = m_Business.Names[0].Text; txtUUID.Text = m_Business.BusinessKey; if (m_Business.Descriptions.Count>0) {     txtDescription.Text = m_Business.Descriptions[0].Text; }

We then iterate through the collection of services that are registered for the business. The ServiceInfos collection is a collection of ServiceInfo objects, and we can use the first entry in the Names collection and the ServiceKey property for each of the members of the collection. These are simply added to the list box on the form:

// Iterate through the services lstServices.Items.Clear(); foreach(ServiceInfo serviceInfo in m_Business.ServiceInfos) {     lstServices.Items.Add(serviceInfo.Names[0].Text + " - "          + serviceInfo.ServiceKey); }

Now that the form has been populated, we can add new services, edit the bindings for an existing service, or delete an existing service from the UBR. We can click Add at any time, but the Delete and Edit buttons become enabled only when we have a service selected in the list box.

Adding and Deleting Services

You add and delete services by clicking the respective buttons on the main form, as shown earlier in Figure 4-21.

Adding a service

Clicking the Add button launches a dialog box in which we can specify a name and a description for the service we want to add. We must provide a name for the service, but the description is optional.

As we pointed out in the discussion of the UDDI SDK, the Save methods require a collection of objects of the correct type to be passed to them. These objects are then used to populate the details in the call to the API.

To save a service, we must create a BusinessService object and populate it with the necessary details. First, we associate the BusinessService object with a business that we have permission to modify. We already have the UUID for the business (which was passed as part of the dialog box creation process and stored as the m_BusinessKey variable), and we simply add this to the BusinessKey property.

Next we add the name and the description of our service to the necessary collections; as you’ll recall, a service can have names and descriptions in multiple languages, so we have to add the details using the Add method of the underlying CollectionBase class:

// Create the object and set the values BusinessService l_Service = new BusinessService(); l_Service.BusinessKey = m_BusinessKey; l_Service.Names.Add (txtName.Text); l_Service.Descriptions.Add (txtDescription.Text);

Once we create the BusinessService object, we can call the static method on the Helper class, SaveService, passing in the BusinessService object we’ve populated.

The Helper.SaveService static method creates a new instance of the SaveService class and adds the received BusinessService object to the BusinessServices collection. Then SaveService calls the Send method to make the call to the UBR:

internal static bool SaveService(BusinessService businessService) {     // Do the save     SaveService saveService = new SaveService();     saveService.BusinessServices.Add (businessService);     saveService.Send(m_Connection);     return(true); }

The Send method returns a ServiceDetail object that contains the details we’ve added to the UBR, along with the new UUID for the service. We could write code to extract the name and the service key from the returned object and add these details to the list of services that the business supports, but in this simple application we won’t do this.

Whenever we add, delete, or edit a service, we force a complete repopulation of the business details. This involves an extra call to the UBR, but it does remove a lot of code from the application and allows us to concentrate on the parts of the application that are specific to the UDDI SDK.

Deleting a service

Deleting a service from the UBR is as simple as specifying the UUID of the service and making a call to the UBR. We retrieve the key from the populated list box with a little bit of string manipulation. We know that the UUIDs that we’re using are 36 characters long, so we simply take the last 36 characters and assign these to a string variable:

string strKey = lstServices.Text.Substring(lstServices.Text.Length - 36);

We then make a call to the static Helper.DeleteService method, passing in the UUID of the service that we want to delete.

The Helper.DeleteService method creates a new instance of the DeleteService class and adds the key that was passed in to the ServiceKeys collection. We then call the Send method of the DeleteService instance:

internal static bool DeleteService(string strServiceKey) {     // Do the delete     DeleteService deleteService = new DeleteService();     DeleteService.ServiceKeys.Add(strServiceKey);     deleteService.Send(m_Connection);     return(true); }

The Send method here also returns a class that we can use to determine the outcome of the delete request. We’re not going to use these details, so we’ll rely on a complete repopulation of the business details form.

Editing a Service

We can select a service and click the Edit button to edit the binding details for the selected service. Although we’re dealing with services, the process is similar to the process for editing the business details, which we’ve already seen. As you can see in Figure 4-22, the form for editing a service is similar to the form for editing the business details.

click to expand
Figure 4-22: Editing the service details

The code that sits behind this form is similar to the code we wrote for the business details screen; we’re simply working with a set of classes that are one step lower down the chain—services instead of businesses.

To open this form, we selected an existing service with a known UUID key (which is passed to the form as part of the form constructor and stored as the m_ServiceKey local variable). In the Query application, we searched for services that met our search criteria and used the find_service API method; because we know the UUID for the service we’re looking for, we can use the get_serviceDetail method in the UDDI API to return the complete details of the service. We’ve wrapped this call in the static GetService method of the Helper class.

The complete code for the Helper.GetService method is shown here. If you compare this code to the code for the Helper.GetForUser method shown earlier, you’ll see that they are remarkably similar. We’re using the GetServiceDetail class, and we add the key of the service that we want to find to the ServiceKeys collection. We can call the Send method and make the call to the UBR.

internal static BusinessService GetService(string strServiceKey)     // Create the GetServiceDetail class     GetServiceDetail getServiceDetail = new GetServiceDetail();     getServiceDetail.ServiceKeys.Add(strServiceKey);     // Make the call     return (getServiceDetail.Send(m_Connection).BusinessServices[0]); }

The Send method actually returns a ServiceDetail object that has a BusinessServices collection of BusinessService objects. If we were to add multiple keys to the ServiceKeys collection before making the call to the Send method, the method would return multiple items in the BusinessServices collection. Because we’ve specified only one key, the Send method returns a ServiceDetail object with only one BusinessService object in its BusinessServices collection.

We save the BusinessService object that the Helper.GetService method returns to the l_Service local variable and use this variable to populate the form. Given that a service can have names in different languages, we simply use the first name in the Names collection. We don’t perform any checks to ensure that a name is present in the Names collection because a service must always have at least one name. The ServiceKey value is extracted from the BusinessService object. We check that the Descriptions collection has at least one description before displaying the first item in the collection on the form.

// Return the details for the service BusinessService l_Service = Helper.GetService(m_ServiceKey); // Populate the page txtName.Text = l_Service.Names[0].Text; txtUUID.Text = l_Service.ServiceKey; if (l_Service.Descriptions.Count>0) {     txtDescription.Text = l_Service.Descriptions[0].Text; }

We then iterate through the BindingTemplates collection to retrieve each of the bindings that the service supports. For the services we used the name of the service, but a binding doesn’t have a name; we can use the AccessPoint object exposed by the BindingTemplate object to identify the binding. We display the contents of the AccessPoint.Text property as well as the UUID of the binding, which is accessible via the BindingKey property, in the list box on the form.

// Iterate through the bindings lstBindings.Items.Clear(); foreach (BindingTemplate bindingTemplate in l_Service.BindingTemplates) {     lstBindings.Items.Add(bindingTemplate.AccessPoint.Text + " - " +         bindingTemplate.BindingKey); }

Now that we’ve populated the form, we can add new bindings, delete existing bindings, or edit the details for the bindings that already exist.

Adding and Deleting Bindings

The process for adding and deleting bindings is the same as for adding and deleting services; we just use a different set of objects.

Adding bindings

As with adding services, we first gather the information we need from the user; in this case, we need the URL of the service as well as an optional description. We use this information to populate l_Binding, a BindingTemplate object. We must first specify the UUID of the service that we want to add the binding to, and this is retrieved from the m_ServiceKey variable (which was populated as part of the construction process for the form). We must then provide the URL details of the AccessPoint object and the URL’s type; in this case, we default to UrlType.Http, but several other values are possible.

BindingTemplate l_Binding = new BindingTemplate(); l_Binding.ServiceKey = m_ServiceKey; l_Binding.AccessPoint.Text = txtURL.Text; l_Binding.AccessPoint.UrlType = UrlType.Http;

Once the l_Binding object has been populated correctly, we call the Helper.SaveBinding method, passing it the BindingTemplate object.

The Helper.SaveBinding method is functionally the same as the Helper.SaveService method. We create a SaveBinding object, add the BindingTemplate we received to the BindingTemplates collection, and call the Send method:

internal static bool SaveBinding(BindingTemplate bindingTemplate) {     // Do the save     SaveBinding saveBinding= new SaveBinding();     saveBinding.BindingTemplates.Add(bindingTemplate);     saveBinding.Send(m_Connection);     return(true); }

When we save the binding, we are returned a BindingDetail object that contains the complete details of what we’ve added to the UBR. Rather than use this object, we’ll again rely on the form being completely repopulated from the UBR. We could write code to use the returned object to keep the form and the UBR synchronized, but we’ve used the repopulation of the form to accomplish the same task.

Deleting bindings

Deleting a binding is also remarkably similar to deleting a service. We can retrieve the key of the binding we want to delete from the list box by retrieving the last 36 characters from the entry:

string strKey = lstBindings.Text.Substring(lstBindings.Text.Length - 36);

We pass this key as the sole parameter to the Helper.DeleteBinding method. The helper method creates an instance of the DeleteBinding class, adds the key of the binding we want to delete to the BindingKeys collection, and calls the Send method:

internal static bool DeleteBinding(string strBindingKey) {     // Do the delete     DeleteBinding deleteBinding = new DeleteBinding();     deleteBinding.BindingKeys.Add(strBindingKey);     deleteBinding.Send(m_Connection);    return(true); }

Editing a Binding

Selecting a binding and clicking the Edit button brings up a form, shown in Figure 4-23, that allows us to modify the details for the binding we’ve selected.

click to expand
Figure 4-23: Editing the binding details

Based on Figure 4-23 and the information about modifying businesses and services, you’re probably expecting the process of editing a binding to be roughly the same. Unfortunately, this isn’t the case. The business and the service have child objects, and we have API methods to deal with these children, but the binding is the lowest level in the hierarchy and doesn’t have any children. It simply contains pointers to tModels. The API has no methods to save these references independent of the binding to which they belong. We have to follow a different paradigm for modifying the bindings.

The clue to the new paradigm lies in the addition of the Save button that is now present on the form. When we added or deleted a new service, we made changes directly to the UBR, but we won’t actually save the changes to the references to the tModels until we’re finished with all the modifications to the binding.

When we add or delete a reference to a tModel, we update the list box that contains the UUIDs for the tModels. Only when we choose to save the changes will the details be sent to the UBR.

Populating the form

The method by which we initially populate the form is the same one you’ve seen for both the business and service details. We call a wrapped method in the helper class, Helper.GetBinding, that accepts the UUID for a binding and returns a BindingTemplate that contains the details for the specified binding.

To retrieve the details for a specified binding, we use the get_bindingDetail API call, which is wrapped by the GetBinding helper method. We simply add the UUID of the binding we want to find to the BindingKeys collection of the class and call the class’s Send method.

internal static BindingTemplate GetBinding(string strBindingKey) {     // Create the GetServiceDetail class     GetBindingDetail getBindingDetail = new GetBindingDetail();     getBindingDetail.BindingKeys.Add(strBindingKey);     // Make the call     return (getBindingDetail.Send(m_Connection).BindingTemplates[0]); }

If we’d added multiple UUIDs to the BindingKeys collection, we might have returned multiple bindings in the BindingTemplates collection of the BindingDetail object that is returned from the Send method. We specified only one UUID, however, so we return only one binding—the first item in the BindingTemplates collection.

Now that we’ve retrieved the binding details, we can use them to populate the form. We first populate the static page details using the AccessPoint.Text and BindingKey properties. Then we iterate through the TModelInstanceInfo objects in the TModelInstanceInfos collection and add the TModelKey values to the list box:

BindingTemplate l_Binding = Helper.GetBinding(m_BindingKey); // Populate the page txtURL.Text = l_Binding.AccessPoint.Text; txtUUID.Text = l_Binding.BindingKey; // Iterate through the bindings lstTModels.Items.Clear(); foreach (TModelInstanceInfo tModelInstanceInfo in     l_Binding.TModelInstanceInfos) {     lstTModels.Items.Add(tModelInstanceInfo.TModelKey); }

Adding a reference to a tModel

To add a reference to a tModel to the binding, we must provide some way of specifying the UUID of the tModel that we want to reference. We could allow the user to type the UUID in manually, but this is far from user-friendly. As shown in Figure 4-24, we’ll allow the user to specify a name or a partial name for the tModel and perform a search for a tModel with that name.

click to expand
Figure 4-24: Searching for tModels

Clicking the Search button calls FindTModels, another static method on the Helper class. We pass in the text we entered in the text box and use the FindTModel class to return a TModelList object that contains all of the matches for the name we entered:

internal static TModelList FindTModels(string strName) {     // Create the FindTModel class     FindTModel findTModel = new FindTModel();     findTModel.Name = new Name(strName);     // Make the call     return (findTModel.Send(m_Connection)); }

The TModelList object has a collection of TModelInfo objects that represent the matches for the search. The list box is simply populated with the contents of the Name and TModelKey properties of the TModelInfo objects for the list we retrieved from the UBR:

// Get the results TModelList tModelList = Helper.FindTModels(txtName.Text); // Iterate and populate the results foreach (TModelInfo tModelInfo in tModelList.TModelInfos) {     lstResults.Items.Add(tModelInfo.Name.Text + " - "         + tModelInfo.TModelKey); }

Selecting the tModel that we want to add a reference to and clicking the Add button closes the screen and adds the selected tModel to the list box. We simply take the UUID of the selected item and add this to the list box that contains the tModel references. The actual addition of the details to the UBR will take place when we save the details for the binding.

Deleting a reference to a tModel

Deleting a reference to a tModel is simplicity itself: we remove the selected item from the list box. The item will actually be deleted from the UBR when we save the details for the binding.

Saving the binding

To save the details of the binding, we can use one of the methods of the helper class that we’ve already discussed: the Helper.SaveBinding method. We used this method to add the details of a new binding to the UBR, and we can now use it to save the updated binding.

As you’ll recall, the Helper.SaveBinding method accepts an instance of the BindingTemplate class, which we simply need to populate with the correct details and pass to the method. We specify values for the BindingKey and ServiceKey properties for the BindingTemplate object (which are passed to the form when it is first created and are stored as local variables), and then we specify the Text and UrlType properties for the BindingTemplate object’s AccessPoint property:

BindingTemplate l_Binding = new BindingTemplate(); // populate the binding template l_Binding.BindingKey = m_BindingKey; l_Binding.ServiceKey = m_ServiceKey; l_Binding.AccessPoint.Text = txtURL.Text; l_Binding.AccessPoint.UrlType = UrlType.Http;

We now iterate through the items in the list box and add these to the BindingTemplate object. When we populated the form earlier, we iterated through the TModelInstanceInfos collection to retrieve the existing references; now we simply add a new TModelInstanceInfo to that collection for every entry in the list box:

// Iterate through the list box and  foreach (string l_strKey in lstTModels.Items) {     // Add to the object     TModelInstanceInfo tModel = new TModelInstanceInfo();     tModel.TModelKey = l_strKey;     l_Binding. TModelInstanceInfos.Add(tModel); }

We then make the call to Helper.SaveBinding, and the details we specified for the binding overwrite the details in the UBR.

Extending the UDDI Browser

As we pointed out earlier, the UDDI Browser application is by no means a complete application. We’ve taken a lot of shortcuts that we’d never take in a real- world application. We’ve also ignored some of the facilities that UDDI provides, such as the use of multiple languages when adding names and descriptions to items.

A fully functioning UDDI browser can be developed—the application we’ve provided here can serve as a starting point for a more complete implementation.

Visual Studio .NET and UDDI

So far, we’ve looked at using the UBRs online and using the UDDI SDK to access the data stored at the UBR directly. Although these are perfectly acceptable ways to use the UBRs, you can also do everything from within Visual Studio .NET.

Searching for Web Services

You can search for a Web service within Visual Studio .NET in two ways—each with its own slight peculiarities.

The easiest way to search for a Web service is from the Start Page, by clicking on the Online Resources tab and then selecting the XML Web Services option. This will immediately present the option to search for Web services. You’ll see at the top of the Web page that you also have the option to register Web services. We’ll explore that option shortly.

You can search in the production environment or in the test environment. These environments are equivalent to the live and test registries that we used earlier. You can also specify the category that you’re searching. These are not the same as the categories we looked at earlier—they are specific to Visual Studio .NET. These categories are defined in the VS Web Service Search Categorization and the microsoft-com:geoweb:2000 taxonomies.

We’re not likely to map our Web services to any of the categories in these taxonomies, so selecting any of the categories in the drop-down list or selecting (All Built-In Categories) will not return any results. We need to select (All Of UDDI) to get any results. This option doesn’t add any category information to the search criteria—it allows only the name to be used as the search criteria.

We can select the test environment, select the (All Of UDDI) option in the Category drop-down list, type NOSBasic in the Search For text box, and click the Go button to return the two services we registered earlier, as shown in Figure 4-25.

click to expand
Figure 4-25: Searching for Web services in Visual Studio .NET

As you can see, we’ve found the two Web services we registered, and we can view the details of a service by clicking on its name (which will take us to the Microsoft UBR) or by clicking on the URL that is presented (which will show us the binding details for the service).

We also have the option of adding a reference to the Web service by clicking the Add As Web Reference To Current Project link. This will add the reference to the currently selected project in Solution Explorer. If we don’t have a project open, we’ll get a dialog box informing us that we must have an open project to add a Web reference.

Note

If the reference we’re adding already exists in Visual Studio .NET, it will be updated; a new reference will not be created.

We can also perform an advanced search by clicking the Advanced button. This launches a new browser window within Visual Studio .NET and takes us to the UBR Web interface that we described earlier.

The other way to add a Web reference is to use the Add Web Reference dialog box. We can choose to search either the UDDI directory or the test UDDI directory. Clicking on either link will launch a Visual Studio–specific section of the Microsoft UBR, as shown in Figure 4-26.

click to expand
Figure 4-26: Using the Add Web Reference dialog box to search for Web services

We have what appear to be the standard options for searching for both services and providers, as well as options to navigate through the categories and search for services that fit into those categories.

By specifying the name of a service, we can obtain details of any matching Web services as well as a link to the WSDL file for the service. Opening the WSDL file for the service will enable the Add Reference button, which you can click to add a reference to the Web service.

Registering Web Services

Although the searching functionality in Visual Studio .NET is similar to the functionality available in the UBRs, the management side of the equation is not the same. In Visual Studio .NET we can create a new Microsoft UBR account and add providers and services to that account, but we cannot modify any details once they have been added to the UBR.

If we launch the Start Page within Visual Studio .NET and again navigate to the XML Web Services option on the Online Resources tab, you’ll see a Register A Service tab that we haven’t discussed yet. We can click this tab and the subsequent Register Your XML Web Service Today link to launch a new browser window within Visual Studio .NET where we can specify whether to use the test or production environment.

Selecting the registry that we require will force us to log in using a Passport account that has already been registered with the UBR. If the Passport account we’re trying to use hasn’t been registered with the UBR, we’ll get an error message with a link to the registration page on the selected UBR.

If we haven’t registered a business with the UBR, we’re asked for a name and a description for our business, as shown in Figure 4-27.

click to expand
Figure 4-27: Adding a business to the Microsoft UBR in Visual Studio .NET

Once we enter the name and description, we can click the Save button to add the new business to the UBR. We must again select the UBR we want to use before we can move on to the next step.

After we registered a business to our UBR account, we must select it (or another business already registered to our UBR account) before we can add the details of the a Web service. We can add the details for the Web service using the form shown in Figure 4-28.

click to expand
Figure 4-28: Adding a service to the Microsoft UBR in Visual Studio .NET

As you can see, we can register the service by specifying, at a minimum, a name, a description, an address for the Web service, and an address for the service’s WSDL file.

If we want to use the VS Web Service Search Categorization and the microsoft-com:geoweb:2000 taxonomies to categorize our Web services, we can select entries from the Service Category and Primary GeoWeb Classification drop-down lists as required.

UDDI Enterprise Services in Windows 2003 Server

So far, we’ve looked at using the public UBRs that are available to every user of the Internet. Earlier in the chapter, we pointed out that it’s not a good idea to use the public UBRs in certain cases and that you can’t use the public UBRs for Web services that are running on an intranet.

Thankfully, there is a solution to this problem: UDDI Enterprise Services, an optional component that is available in the Standard, Enterprise, and Datacenter editions of Windows Server 2003. UDDI Enterprise Services provides a completely functional UBR that implements the requirements of version 2 of the UDDI specification.

Using the local UBR provided by UDDI Enterprise Services is virtually identical to using any of the public UBRs, so we can use all the knowledge we’ve gained so far in the chapter.

Note

When you use UDDI Enterprise Services, you don’t have the limits imposed on the providers, services, and tModels that you have when you use the public UBRs. With the public UBR, you can only have one provider per account, but the local UBR allows you to have as many providers per account as you want. The same also applies to services and tModels.

A few little details are slightly different between the public and private UBRs, as detailed in the upcoming sections.

Authentication

UDDI Enterprise Services installs with two versions of the local UBRs, which by default are at http://localhost/uddi/ and http://localhost/uddipublic/. If you inspect how these are configured within IIS, you can see that they are virtual directories that point at the same physical directory on the server. The difference between the two directories is that the first requires a valid Windows account for access and the second allows anonymous access.

Forcing users to have a valid Windows account before they can access the UBR allows us to determine, as you’ll shortly see, what role the user has and what he is allowed to accomplish on the server. The anonymous access allowed by the second UBR allows the user only to search the UBR; we have no means of determining who the user is, so we cannot give the user a higher level of access.

Roles in UDDI Enterprise Services

As we mentioned briefly, access to http: //localhost/uddi/ is controlled using Windows authentication, and the user must have a valid Windows account to access the UBR. The permissions within the UBR are determined by the role the user has been granted.

There are four roles within UDDI Enterprise Services, each with different permissions within the UBR. The roles and their permissions are listed in Table 4-8.

Table 4-8: Roles Defined in UDDI Enterprise Services

Role

Permissions

User

Can search the UBR

Publisher

The preceding permissions, plus permission to publish information in the UBR

Coordinator

All of the preceding permissions, plus

  • Can modify information belonging to other users and can change the ownership of existing information

  • Can view UBR statistics

  • Can modify and delete existing category taxonomies

Administrator

All of the preceding permissions, plus permission to import data, including category taxonomies, from other sources

To determine which role a Windows account belongs to, UDDI Enterprise Services allows a Windows group to be assigned to each of the roles. By default, the BUILTIN/Administrators group maps to the Publisher, Coordinator, and Administrator roles, and the BUILTIN/Users group maps to the Users role. As shown in Figure 4-29, you can change these mappings in the Properties dialog box for a UBR instance within Management Console.

click to expand
Figure 4-29: Managing roles with UDDI Enterprise Services

You can specify any of the Windows groups that are valid on the server, whether they are local (as we’ve used here) or controlled across a domain. When a user matches a role, that user will be given the permissions appropriate to that role. If the user belongs to a group that doesn’t have a mapping to a role, he will be placed in the Users role.

UDDI Enterprise Services and the UDDI SDK

We can use a local UBR with the UDDI SDK with minimal change to the code that we wrote for accessing a public UBR. The only change needed is in the way that we create the UddiConnection object that we use to talk to the UBR.

When we created the UddiConnection object earlier, we used UDDI Authentication and passed in the username and password that we wanted to use. If we use a different version of the UddiConnection constructor, we can set it to use Windows Authentication instead.

We can replace the code in the Helper.Connect method with the following to access the UBR running on the local machine using Windows Authentication:

m_Connection = new UddiConnection(     "http://localhost/uddi/inquire.asmx",     "http://localhost/uddi/publish.asmx" );

We don’t need to make any other changes to the Browser application to use the local instance of the UBR. The request for the AuthToken from the UBR as well as adding it to any requests to the Publishing API is handled by the UDDI SDK automatically.




Programming Microsoft. NET XML Web Services
Programming MicrosoftВ® .NET XML Web Services (Pro-Developer)
ISBN: 0735619123
EAN: 2147483647
Year: 2005
Pages: 172

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net