Building Enterprise Web Services


Creating a new Web service in Visual Studio .NET is easy because the New Project Wizard does just about everything for you. In general, the steps to creating a new Web service involve creating a new project, implementing the Web service methods , testing the service, and building a service client.

In Visual Studio .NET, building Web services is similar to building Web forms. Rather than having an .aspx file extension, Web services have an .asmx extension. Both file types also have a code-behind page with an additional .cs file extension. The biggest difference is that Web services have no user interface elements. They are essentially used for machine-to-machine data exchange only.

Expanding the Web Service Project

The IssueTracker enterprise application will leverage the power of Web services to expose existing data and services to third-party integrators. Any client application interested in accessing Issues or Users managed by IssueTracker only needs to send and receive SOAP messages.

As part of the Visual C# Distributed Application project, Visual Studio .NET has already created a Web service project containing a single default Web service identified as WebService1.asmx . The existing Web service project resides under the C:\Inetpub\ wwwroot \IssueTracker_WebService directory. From the Solution Explorer, select WebService as the startup project type.

Because the Web service project will expose functionality provided by the Business Facade project, you need to create a reference to the Business Facade project. Open the Solution Explorer and select the References node under the Web service project. Next, open the pop-up menu and select Add Reference. In the Add Reference dialog box, select the Business Facade project, click Select, and then click OK to close the box.

Adding a New Web Service

Currently, Web services have little to offer in the area of security. They are based upon a technology stack of openly published specifications, their messages and content are transmitted in plain-text XML, and their request and response messages are typically transmitted over the open HTTP. A new specification, WS-Security, is in the works to resolve security concerns. For now, however, it is up to the individual developer to implement security functionality.

One of the most common, and minimal, approaches to Web service security is to implement an access key approach. In this approach, a user makes an initial Web service call, providing login credentials encrypted over a secure HTTPS connection. The program validates the login and returns an access key. All sub-sequent Web service method invocations then require the same valid key to perform its service.

The IssueTracker application will implement a new Web service that receives the login credentials, validates them with the help of the existing LoginManager, generates a new access key, and returns that key to the Web service caller. Begin by returning to the Solution Explorer and setting the Web service project as the startup project. Next, open the project's pop-up menu and select Add ˜ Add Web Service. The familiar Add New Item dialog box appears with the Web Service icon already highlighted. Enter LoginServices.asmx for the new Web service file- name , as shown in Figure 9-5.

click to expand
Figure 9-5: Creating a new Web service with the Add New Item dialog box

Visual Studio .NET creates a new LoginServices.asmx file and displays it in the design view. Because you can do little in the design view, switch to the code view by clicking the Switch to Code View link. The Web service source code is minimal. The necessary namespace references are in place, along with a class definition, a default constructor, and a couple of methods that initialize and dispose of the object. However, the file compiles cleanly into a Web service with no methods. To implement the ValidateLogin method within the LoginServices Web service, add the source code shown in Listing 9-7.

Listing 9-7: LoginServices.cs in the Web Service Project
start example
 [WebMethod(EnableSession=true)] public string ValidateLogin( string strEmailAddress, string strPassword ) {     //instantiate the LoginManager object     UserManager mgrLogin = new UserManager();     //validate login by getting the user data     User objUser = mgrLogin.GetUser( strEmailAddress, strPassword );     if( objUser != null )     {         //if successful, return the key         if( Session[strEmailAddress] == null )             Session[strEmailAddress] = 1;         return Session.SessionID;     }     //if not successful, return error message     return "ERR: Unable to validate login."; } 
end example
 

This method begins with a WebMethod attribute. Attaching the WebMethod attribute to a public method indicates that the method is to be exposed as part of an XML Web service. The EnableSession parameter indicates whether session state is enabled for the Web service. Otherwise , a Web service method appears just like any other method within the framework:

 [WebMethod(EnableSession=true)] 

First, the code creates an instance of the LoginManager object. Next, the Web service parameters pass to the ValidateLogin method to authenticate the supplied credentials. If the program approves the login credentials, then it generates an access key and returns to the Web service caller.

You can generate a unique access key in any number of ways. The IssueTracker application creates an HttpSessionState variable to store the e-mail address of the user logging in:

 Session[strEmailAddress] = 1; 

The SessionID property serves as a nice key because it is unique, it can be tied back to a specific login, and it has a built-in expiration. You can easily complement the ValidateLogin method with another that checks to determine if the access key is valid. Add the method shown in Listing 9-8 to the same source file.

Listing 9-8: Adding Capability to Validate a Login Key
start example
 [WebMethod(EnableSession=true)] public string CheckKey( string strKey ) {     //determine if key is still valid     if( Session.SessionID.CompareTo( strKey ) == 0 )         return "OK: The Key is still valid.";     else         return "ERR: The Key is not valid."; } 
end example
 

This method takes the access key generated by the ValidateLogin Web service method and determines if it is valid. Because the access key is essentially the SessionID value for the caller of this method, this method only needs to perform a quick comparison. With the two most important Web service methods complete, it is time to test them.

Testing a New Web Service

Visual Studio .NET makes testing Web services just as easy as writing them. With the Web service project selected as the startup project, run the debugger by pressing F5. The LoginServices test page displays, listing the two public Web service methods, as shown in Figure 9-6. Each method displays a link to a page that tests that specific method. Begin by clicking the ValidateLogin link.

click to expand
Figure 9-6: The LoginServices Web service test page
Note  

A number of developers have experienced problems debugging Web services, receiving the following error: "Unable to generate a temporary class (result=1)." To resolve the problem, try modifying the security permissions on the specified directory by adding a new user, named machine_name\aspnet, and assigning it full directory privileges. See MSDN Article #Q322886 at http://support.microsoft.com/default.aspx?scid=kb%3ben-us%3b322886 for more information.

Clicking the method name displays another test page, as shown in Figure 9-7. This page lists the method parameters along with fields to enter test parameters. Next, enter a valid IssueTracker login or the word test for the e-mail address and password and then click the Invoke button.

click to expand
Figure 9-7: Testing the ValidateLogin Web service method

The results of the Web service display in an XML document. In this case, the test returns a cryptic string that represents the access key for unlocking the remaining Web services:

 <?xml version="1.0" encoding="utf-8" ?> <string xmlns="http://tempuri.org/">qd1ai155wf5tpn45wgjfx223</string> 

As an additional test, return to the initial test page and click the CheckKey link. In the CheckKey method test page, enter the same access key and click the mInvoke button. If all goes well, the result should be the following confirmation message:

 <?xml version="1.0" encoding="utf-8" ?> <string xmlns="http://tempuri.org/">OK: The Key is still valid.</string> 

The Web service method test page also provides additional debugging information. Specifically, it displays the actual SOAP request and response messages coming to and from the Web service.

Examining the SOAP Request

A SOAP request comprises two elements, the HTTP request and the XML content that supplies the method parameters. Even without an explanation of the SOAP specification, it is not difficult to understand what most of it means. This is radically different from the CORBA and Distributed Component Object Model (DCOM) protocols, which are binary, not self-describing , and difficult to trace.

Although HTTP is used to deliver SOAP messages, SOAP can be carried over any other transport protocol, including Simple Mail Transfer Protocol (SMTP), the Internet e-mail protocol. The header differs between transport layers , but the XML content remains the same:

 POST /IssueTracker_WebService/LoginServices.asmx HTTP/1.1 Host: localhost Content-Type: text/xml; charset=utf-8 Content-Length: length SOAPAction: "http://tempuri.org/ValidateLogin" <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">   <soap:Body>     <ValidateLogin xmlns="http://tempuri.org/">       <strEmailAddress>string</strEmailAddress>       <strPassword>string</strPassword>     </ValidateLogin>   </soap:Body> </soap:Envelope> 

A SOAP request is typically sent as an HTTP POST request with the content type set to text/xml and a SOAPAction field set to either an empty string or the name of the SOAP method. The SOAPAction field informs a Web server that an incoming SOAP message is on the way so that it can process, route, or filter the request. When the Web server receives the request, it first checks that the request has a SOAPAction field. If it does, it forwards it to the destination .asmx file; otherwise, it redirects to the default Web service test page.

The XML content of the SOAP request comes in three sections: the Envelope, Header, and Body. The Envelope defines the namespaces used by the rest of the SOAP message. Table 9-2 describes these namespaces.

Table 9-2: Summary of the SOAP Envelope Namespaces

NAMESPACE

DESCRIPTION

xmlns:SOAP-ENV

SOAP Envelope namespace

xmlns:xsi

XML schema for instances

xmlns:xsd

XML schema for data types

The Header is optional; it carries extended information relating to authentication, transactions, and payments. Any element in a SOAP processing chain can add or delete items from the Header. If a Header is present, it must be the first child node of the Envelope. Because the ValidateLogin method is simple and contains extended information, the Header is absent.

The Body represents the main content of the message. When SOAP performs a Web service method invocation, the Body contains a single element that includes the method name, arguments, and Web service target address. The Body element must be the first child element of the Header element. If the Header element is not present, then the Body element must be the first child of the Envelope element. The first child node of the Body element identifies the Web service method to be invoked. That element's children represent the parameters passed to the method.

The SOAP parameters can either be typed or untyped. The default SOAP encoding scheme uses the xsi:type attribute to indicate an XSD type. XSD defines several basic types, including int, byte, short, boolean, string, float, double, date, time, and URL. It also specifies a format for sending arrays and blocks of opaque data. Because SOAP is intended to be platform and language neutral, XSD does not define formats for encoding objects or structures unique to a single language.

Examining the SOAP Response

A SOAP/HTTP response is also returned as an XML document within a standard HTTP reply whose content type is set to text/xml. The XML document structure is just like the request except that the Body contains the encoded method result. The namespace of the result is the original target object URI, and the base name is the name of the method that was invoked. The XSI/XSD tagging scheme is optionally used to denote the type of the result. The SOAP standard does not specify what should be returned from a void method, but most implementations simply omit the <return> tag of the Body:

 HTTP/1.1 200 OK Content-Type: text/xml; charset=utf-8 Content-Length: length <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">   <soap:Body>     <ValidateLoginResponse xmlns="http://tempuri.org/">       <ValidateLoginResult>string</ValidateLoginResult>     </ValidateLoginResponse>   </soap:Body> </soap:Envelope> 

Exposing Existing Services As Web Services

As with most enterprise applications, the purpose of the Web service project is to expose the IssueTracker application functionality for integration into other applications or processes. Therefore, the remainder of the IssueTracker Web service should be dedicated to wrapping the functionality already implemented within the Business Facade project. Because the Business Facade project contains the functionality already packaged within objects, such as IssueManager and UserManager, it makes sense to implement Web services similarly packaged, such as IssueServices and UserServices. An example of wrapping an existing method appears in Listing 9-9 as the GetSpecificIssue Web service method wraps the GetSpecificIssue Business Facade method.

Listing 9-9: IssueServices.cs in the Web Service Project
start example
 [WebMethod(EnableSession=true)] public string GetSpecificIssue( string strKey, int argIssueID ) {     //check key     LoginServices svcLogin = new LoginServices();     if( svcLogin.CheckKey( strKey ).StartsWith( "OK" ) )     {         BusinessFacade.IssueManager mgrIssues = new             BusinessFacade.IssueManager();         return mgrIssues.GetSpecificIssueXml( argIssueID );     }     return null; } 
end example
 

Similar to a new Web service method, the implementation begins with the WebMethod property. However, rather than returning a simple string value as in the previous example, this method returns a longer string that represents a DataSet in XML. The method accepts two input parameters: the access key and an identifier indicating which Issue data to return. After validating the access key, the method creates a new IssueManager object and invokes the GetSpecificIssueXml method outlined in Listing 9-10.

Listing 9-10: Implementing the GetSpecificIssueXml Business Facade Method
start example
 public string GetSpecificIssueXml( int argLongIssueID ) {     string strOutput;     Issue objIssue = new Issue();     strOutput = _ObjectManager.SelectOneAsXML( objIssue, argLongIssueID );     return strOutput; } 
end example
 

The GetSpecificIssueXml method appears in the Business Facade project and is similar to the GetSpecificIssue method. The difference between the two methods is probably obvious: In one case, an Issue object is returned, and in the other, a string is returned that formats the Issue as XML. Otherwise, this method works just like its GetSpecificIssue counterpart . It creates a new Issue object and passes it along with an ID to the business object manager.

The business object manager implemented within the DataAccess project adds a new public method that selects a specific Issue and returns it as XML rather than an Issue business object. Listing 9-11 implements the new SelectOneAsXml method.

Listing 9-11: Retrieving an Issue Record As XML
start example
 public string SelectOneAsXML( BusinessObject objSource, int intObjectID ) {     bool boolStatus = false;     string strObject;     string strStoredProc;     string strOutput = "";     SqlParameter parameter;     SqlCommand command;     try     {         //get the object name         Type objType = objSource.GetType();         strObject = objType.FullName.Substring( objType.FullName.IndexOf(".")+1);         //get the stored procedure name         strStoredProc = "app_";         strStoredProc += strObject;         strStoredProc += "SelectAsXml";         //initialize the command         command = new SqlCommand( strStoredProc, dataComponent.sqlConnection );         command.CommandType = CommandType.StoredProcedure;         //add the ID parameter         parameter = new SqlParameter( "@" + strObject + "ID", SqlDbType.Int );         parameter.Direction = ParameterDirection.Input;         parameter.Value = intObjectID;         command.Parameters.Add( parameter );         //open the connection and execute query         dataComponent.sqlConnection.Open();         XmlReader reader = command.ExecuteXmlReader();         reader.MoveToContent();         strOutput = reader.ReadOuterXml();         reader.Close();     }     catch( Exception exception )     {         EventLog systemLog = new EventLog();         systemLog.Source = "IssueTracker";         systemLog.WriteEntry( exception.Message, EventLogEntryType.Error, 0 );     }     finally     {         dataComponent.sqlConnection.Close();     }     return strOutput; } 
end example
 

The SelectOneAsXml method is a variation of the existing SelectOne method. The only minor differences include a new stored procedure, a different data reader, and a different return type. The new stored procedure appears in Listing 9-12 and differs by adding the FOR XML AUTO statement described in Chapter 2, "Accessing Data in ADO.NET." Instead of processing records with a SqlDataReader, records are processed with an XmlReader object. The XmlReader produces a string value containing an XML representation of the selected Issue.

Listing 9-12: The app_IssueSelectAsXml Database Stored Procedure
start example
 CREATE PROCEDURE dbo.app_IssueSelectAsXml (     @IssueID int ) AS SET NOCOUNT ON; SELECT IssueID, TypeID, UserID, EntryDate, StatusID, Summary, Description, PriorityID, ModifiedDate FROM Dat_Issue WHERE (IssueID = @IssueID) FOR XML AUTO; GO 
end example
 

The modified stored procedure returns a string that represents the Issue in XML format. Otherwise, it appears almost identical to its app_IssueSelect counterpart. Listing 9-13 presents an example of the XML code produced as a result of the new query.

Listing 9-13: XML Output from the GetSpecificIssue Web Service Method
start example
 <?xml version="1.0" encoding="utf-8" ?> <string xmlns="http://tempuri.org/"><Dat_Issue IssueID="1" TypeID="1"     UserID="1" EntryDate="2002-01-01T00:00:00" StatusID="1"     Summary="Unable to print. " Description="Can not print to the color laser     in the copy room." PriorityID="2" ModifiedDate="2002-01-01T00:00:00" /> </string> 
end example
 

Changing the Default Namespace

As Web services emerge, there may be cases where Web service names and method names will collide. As mentioned earlier, namespaces uniquely identify a Web service method. By default, Visual Studio .NET assigns the default namespace of http://tempuri.org/ . To change from this default, edit the namespace accordingly :

 [ WebMethod( EnableSession=true, Namespace="http://www.mynamespace.net/webservices/" ) ] 

Addressing Web Service Security

Initially, developers saw SOAP as an HTTP-based protocol and assumed that HTTP security would be adequate for SOAP. This was largely driven by the fact that thousands of Web applications are running daily using HTTP security. Therefore, the current SOAP standard assumes that security is a transport issue, relying upon technologies such as HTTPS and digitally signed certificates.

As SOAP extended its reach to become a more general-purpose protocol running on top of a number of transports and on a number of devices, security became a bigger issue. HTTP provides several ways to authenticate which user is making a SOAP call, but there are no means to propagate this identity when the message is routed from HTTP to an SMTP transport.

Specifications are already in the works to build upon SOAP to provide additional security features for Web services. The WS-Security specification defines a complete encryption framework, and the WS-License specification defines techniques for guaranteeing the identity of the client and ensuring that only authorized clients can use a Web service. In the meantime, it is up to the enterprise developer to implement a sufficient level of security. The access key approach to Web service access is a common practice.

Building a Web Service Client

As mentioned, a Web service client can take many shapes including other Web services, Web applications, desktop applications, console applications, cellular phones, Personal Digital Assistants (PDAs), and any other device capable of sending and receiving SOAP messages. To demonstrate , let's implement the application login functionality of the IssueTracker Windows form application using LoginServices.

Begin by opening the Solution Explorer in Visual Studio .NET and selecting the WinUI project as the startup project. Next, open the pop-up menu for the WinUI project and select Add Web Reference. When the Add Web Reference dialog box appears, enter the Uniform Resource Locator (URL) that points to the LoginServices Web service file in the Address field of the Add Web Reference dialog box:

http://127.0.0.1/IssueTracker_WebService/LoginServices.asmx

After entering the Web service URL and clicking the Go button, you will see the Web service test page. Enter the namespace associated with the Web service. Generally, Web service namespaces are the reverse designations of domain names, such as net.mynamespace.www, as shown in Figure 9-8.

click to expand
Figure 9-8: Importing a service with the Add Web Reference dialog box

The Web service test page displays the two Web service methods created earlier. Alternatively, you can browse the Microsoft UDDI registry for available Web services by clicking the Add Web Reference button in Visual Studio. The Solution Explorer updates with a new Web References node. This node displays a reference to the locally hosted LoginServices Web service, as shown in Figure 9-9.


Figure 9-9: The Web references associated with the IssueTracker WinUI project

When Visual Studio .NET creates a Web reference to a Web service, it also implicitly creates a new proxy class. This proxy class abstracts the Web service and provides an object that can be instantiated and interacted with in code. The enterprise developer is not concerned with structuring SOAP messages and using HTTP methods to invoke a remote Web service. Rather, you create and invoke a Web service object just as any other C# object. Listing 9-14 interacts with a LoginServices proxy object to validate an IssueTracker login.

Listing 9-14: FormLogin.cs in the WinUI Project
start example
 private void btnOK_Click(object sender, System.EventArgs e) {     string strWebServiceResponse = "";     net.mynamespace.www.LoginServices wsLogin =         new net.mynamespace.www.LoginServices();     strWebServiceResponse = wsLogin.ValidateLogin( edtEmail.Text,         edtPassword.Text );     if( strWebServiceResponse.StartsWith( "ERR" ) == false )     {         m_strAccessKey = strWebServiceResponse;         m_boolLoggedIn = true;         Close();     }     else         System.Windows.Forms.MessageBox.Show( "Login Failed." );     return; } 
end example
 

This event handler begins by instantiating the Web service proxy object. The Web reference listed in the Solution Explorer indicates that the namespace for this object would be net.mynamespaces.www.LoginServices. The object is initialized and the login credentials are supplied as parameters to the ValidateLogin method. The results of the Web service method are returned in a string variable for the event handler to interpret. Depending upon the results of the Web service, the event handler either accepts the login or rejects it.

Interpreting the Web Service Description

As mentioned, a WSDL document describes the interfaces and bindings of a Web service. Web services are collections of network endpoints, known as ports . These ports are identified with network bindings that enable description reuse. The protocol and data format for a specific port represents a binding. Therefore, you define a port by associating a network address with a reusable binding. Table 9-3 summarizes the key elements found in the WSDL document.

Table 9-3: Tag Elements That Define the WSDL Specification

ELEMENT

DESCRIPTION

Types

A container for data type definitions using a type system, such as XSD

Message

An abstract definition of the data being communicated

Operation

An abstract description of an action supported by the service

Port Type

An abstract set of operations supported by one or more endpoints

Binding

A concrete protocol and data format specification for a particular port type

Port

A single endpoint defined as a combination of a binding and a network address

Service

A collection of related endpoints

A completely filled WSDL document can span several pages depending on the number of different data type and methods defined for the Web service. The following code listings present the WSDL document for the LoginServices Web service. The listing has five major blocks.

As you can see in Listing 9-15, the WSDL document begins with a basic page declaration and identifies the document encoding format. Next, the XML namespaces are defined in the definitions block of the WSDL document.

Listing 9-15: The Definitions Element of a Sample WSDL File
start example
 <?xml version="1.0" encoding="utf-8" ?> <definitions xmlns:http="  http://schemas.xmlsoap.org/wsdl/http/  "     xmlns:soap="  http://schemas.xmlsoap.org/wsdl/soap/  "     xmlns:s="  http://www.w3.org/2001/XMLSchema  " xmlns:s0="  http://tempuri.org/  "     xmlns:soapenc="  http://schemas.xmlsoap.org/soap/encoding/  "     xmlns:tm="  http://microsoft.com/wsdl/mime/textMatching/  "     xmlns:mime="  http://schemas.xmlsoap.org/wsdl/mime/  "     targetNamespace="  http://tempuri.org/  "     xmlns="http://schemas.xmlsoap.org/wsdl/"> 
end example
 

With the page declaration and namespace definition out of the way, the WSDL defines the data types referenced by the Web service methods (see Listing 9-16). This block comprises four principal entries that represent the SOAP messages transmitted to and from each Web service method. Each message identifies the piece of data it is carrying. For example, the message that invokes the ValidateLogin method carries two string data elements, named strEmailAddress and strPassword. The message generated in response to this method is ValidateLoginResponse and carries a single string data element, named ValidateLoginResult.

Listing 9-16: The Types Element of a Sample WSDL File
start example
 <types> <s:schema elementFormDefault="  qualified  "     targetNamespace="  http://tempuri.org/  ">  <s:element name="ValidateLogin">  <s:complexType>             <s:sequence>                  <s:element minOccurs="   " maxOccurs="  1  " name="  strEmailAddress  "                     type="  s:string  "/>                 <s:element minOccurs="   " maxOccurs="  1  " name="  strPassword  "                     type="  s:string  " />             </s:sequence>         </s:complexType>     </s:element>  <s:element name="ValidateLoginResponse">  <s:complexType>             <s:sequence>                  <s:element minOccurs="   " maxOccurs="  1  "                     name="  ValidateLoginResult  " type="  s:string  " />             </s:sequence>         </s:complexType>     </s:element>  <s:element name="CheckKey">  <s:complexType>             <s:sequence>                  <s:element minOccurs="   " maxOccurs="  1  " name="  strKey  "                      type="  s:string  " />             </s:sequence>         </s:complexType>     </s:element>  <s:element name="CheckKeyResponse">  <s:complexType>             <s:sequence>                  <s:element minOccurs="   " maxOccurs="  1  " name="  CheckKeyResult  "                     type="  s:string  " />                 </s:sequence>             </s:complexType>         </s:element>         <s:element name="  string  " nillable="  true  " type="  s:string  " />     </s:schema>     </types> 
end example
 

The message element describes the data being exchanged between the Web service providers and consumers (see Listing 9-17). Each Web method has two messages: input and output. The input describes the parameters for the Web method; the output describes the return data from the Web method. Each message contains zero or more <part> parameters, one for each parameter of the Web method. Each parameter associates with a concrete type defined in the <types> container element

Listing 9-17: The Message Element of a Sample WSDL File
start example
 <message name="ValidateLoginSoapIn">     <part name="  parameters  " element="  s0:ValidateLogin  " /> </message> <message name="  ValidateLoginSoapOut  ">     <part name="  parameters  " element="  s0:ValidateLoginResponse  " /> </message> <message name="  CheckKeySoapIn  ">     <part name="  parameters  " element="  s0:CheckKey  " /> </message> <message name="  CheckKeySoapOut  ">     <part name="  parameters  " element="  s0:CheckKeyResponse  " /> </message> <message name="  ValidateLoginHttpGetIn  ">     <part name="  strEmailAddress  " type="  s:string  " />     <part name="  strPassword  " type="  s:string  " /> </message> <message name="  ValidateLoginHttpGetOut  ">     <part name="  Body  " element="  s0:string  " /> </message> <message name="  CheckKeyHttpGetIn  ">     <part name="  strKey  " type="  s:string  " /> </message> <message name="  CheckKeyHttpGetOut  ">     <part name="  Body  " element="  s0:string  " /> </message> <message name="  ValidateLoginHttpPostIn  ">     <part name="  strEmailAddress  " type="  s:string  " />     <part name="  strPassword  " type="  s:string  " /> </message> <message name="  ValidateLoginHttpPostOut  ">     <part name="  Body  " element="  s0:string  " /> </message> <message name="  CheckKeyHttpPostIn  ">     <part name="  strKey  " type="  s:string  " /> </message> <message name="  CheckKeyHttpPostOut  ">     <part name="  Body  " element="  s0:string  " /> </message> 
end example
 

Ports are channels through which Web service request and response messages are communicated. Ports types might include SOAP, HTTP-GET, HTTP-POST, and SMTP. You need to map each port type to specific Web service methods, which in turn map to the specific messages that carry data to and from the Web service. To map a method to a request-response pair of messages, they must appear in the <operation> element (see Listing 9-18).

Listing 9-18: The Ports and Channels Element of a Sample WSDL File
start example
 <portType name="  LoginServicesSoap  ">     <operation name="  ValidateLogin  ">         <input message="  s0:ValidateLoginSoapIn  " />         <output message="  s0:ValidateLoginSoapOut  " />     </operation>     <operation name="  CheckKey  ">         <input message="  s0:CheckKeySoapIn  " />         <output message="  s0:CheckKeySoapOut  " />     </operation> </portType> <portType name="  LoginServicesHttpGet  ">     <operation name="  ValidateLogin  ">         <input message="  s0:ValidateLoginHttpGetIn  " />         <output message="  s0:ValidateLoginHttpGetOut  " />     </operation>     <operation name="  CheckKey  ">         <input message="  s0:CheckKeyHttpGetIn  " />         <output message="  s0:CheckKeyHttpGetOut  " />     </operation> </portType> <portType name="  LoginServicesHttpPost  ">     <operation name="  ValidateLogin  ">         <input message="  s0:ValidateLoginHttpPostIn  " />         <output message="  s0:ValidateLoginHttpPostOut  " />     </operation>     <operation name="  CheckKey  ">         <input message="  s0:CheckKeyHttpPostIn  " />         <output message="  s0:CheckKeyHttpPostOut  " />     </operation> </portType> 
end example
 

Bindings specify how Web service methods expect the data to be encoded. The SOAP specification contains predefined rules for doing this. This involves a transition from abstract data types, messages, and operations to concrete physical representations of the messages transmitted. The concrete aspects of operations are defined in the <binding> element (see Listing 9-19).

Listing 9-19: The Types Operations of a Sample WSDL File
start example
 <binding name="LoginServicesSoap" type="s0:LoginServicesSoap">     <soap:binding transport="http://schemas.xmlsoap.org/soap/http"         style="  document  " />  <operation name="ValidateLogin">  <soap:operation soapAction="  http://tempuri.org/ValidateLogin  "             style="  document  " />         <input>              <soap:body use="  literal  " />         </input>         <output>              <soap:body use="  literal  " />         </output>     </operation>  <operation name="CheckKey">  <soap:operation soapAction="  http://tempuri.org/CheckKey  "             style="  document  " />         <input>             <soap:body use="  literal  " />         </input>         <output>             <soap:body use="  literal  " />         </output>     </operation> </binding> <binding name="  LoginServicesHttpGet  " type="  s0:LoginServicesHttpGet  ">     <http:binding verb="  GET  " />  <operation name="ValidateLogin">  <http:operation location="  /ValidateLogin  " />         <input>              <http:urlEncoded />         </input>         <output>              <mime:mimeXml part="  Body  " />         </output>     </operation>  <operation name="CheckKey">  <http:operation location="  /CheckKey  " />         <input>              <http:urlEncoded />         </input>         <output>              <mime:mimeXml part="  Body  " />         </output>      </operation> </binding> <binding name="  LoginServicesHttpPost  " type="  s0:LoginServicesHttpPost  ">     <http:binding verb="  POST  " />  <operation name="ValidateLogin">  <http:operation location="  /ValidateLogin  " />         <input>              <mime:content type="  application/x-www-form-urlencoded  " />         </input>         <output>              <mime:mimeXml part="  Body  " />         </output>     </operation>  <operation name="CheckKey">  <http:operation location="  /CheckKey  " />         <input>              <mime:content type="  application/x-www-form-urlencoded  " />         </input>         <output>              <mime:mimeXml part="  Body  " />         </output>     </operation> </binding> 
end example
 

The name of the binding can be anything, but you must use the same name for the binding attribute of the <port> element. Inside the <binding> element, there is an extension element called <soap:binding>. It specifies the transport protocol used, whether it is HTTP or SMTP, and the style of request.

Finally, the <service> element defines the interface for the entire Web service with the exposed Web service name defined as an element attribute (see Listing 9-20). This element also identifies endpoints publicly available and maps them to the ports defined earlier in the WSDL. In all three cases, the SOAP endpoints map to a single .asmx Web service implementation file

Listing 9-20: The Service Element of a Sample WSDL File
start example
 <service name="  LoginServices  ">     <port name=  "LoginServicesSoap"  binding="  s0:LoginServicesSoap  ">         <soap:address  location="  http://localhost/Issue.../LoginServices.asmx  " />     </port>     <port name="  LoginServicesHttpGet  " binding="  s0:LoginServicesHttpGet  ">         <http:address location="  http://localhost/Issue.../LoginServices.asmx  " />     </port>     <port name="  LoginServicesHttpPost  " binding="  s0:LoginServicesHttpPost  ">         <http:address location="  http://localhost/Issue.../LoginServices.asmx  " />     </port> </service> </definitions> 
end example
 

It quickly becomes clear how a WSDL specification for a Web service can be self-describing. The <service> element represents the entry point for the entire Web service. This element describes the service in terms of entry points, referred to as ports . The <binding> element maps these ports to a specific communication protocol. The <portType> element maps defined ports to Web service methods, referred to as operations . Each <operation> element comprises an input and output message. Each <message> element defines parts of its message and, in some cases, references a parameter data structure. These data structures are defined in the <Types> element. Finally, all blocks come together to comprehensively describe a single Web service for publishing.

Publishing Web Service Availability

As mentioned, UDDI is a technology that lets Web service clients dynamically find Web service providers. You can browse a UDDI registry by service descriptions or by businesses descriptions. The results of a UDDI search provide information about the business or service. Most important, UDDI entries provide WSDL descriptions of Web services, allowing a client to dynamically bind to the listed Web service without requiring any other integration information. The typical process for using UDDI is in a publish-find-bind process, as illustrated in Figure 9-10.

click to expand
Figure 9-10: The relationship between Web service provider, registrar, and client

A provider of Web services registers itself and publishes its available services. This information appears in the UDDI White Pages. Business information such as the name, address, telephone number, and other contact information becomes available for others to find. This business information is stored in a BusinessEntity object, which in turn contains information about services, categories, contacts, URLs, and other documents relating to that business.

Web service clients use UDDI to find a specific Web service. Organized information about Web services appear in the UDDI Yellow Pages. This information groups Web services by common functionality and stores them in a BusinessService object.

Web service clients connect to and interact with Web services after they have found them. Technical information about Web services, including the details necessary to invoke a Web service, appear in the UDDI Green Pages. This includes URLs, information about method names, argument types, and related documents, which are stored in the BindingTemplate object. Web service specifications are defined in a UDDI document called a type model or tModel . Usually, the tModel contains a WSDL file that describes a SOAP interface to a Web service.

Developers and organizations can publish the availability of Web services with any available UDDI registry. You can find information about registering as an organization and publishing an available Web service at http://uddi.microsoft.com .

Discovering Web Services with UDDI

You browse a UDDI registry through a Web service. Web service clients can connect to the Microsoft UDDI registry by pointing to the UDDI Inquiry interface:

http://uddi.microsoft.com/ inquire

Just as your own Web services have a test page, the Microsoft UDDI Inquiry Web service also provides a Web browser-supported test page. All public Web service methods display, including those that return business, service, binding, and tModel details. An easier method of searching the UDDI registry is through the Add Web Reference dialog box, as shown in Figure 9-11.

click to expand
Figure 9-11: Searching for external Web services in the UDDI registry

To find information about a business or service, enter the name into the displayed edit field. In Figure 9-11, the user has entered Microsoft as the provider name. This has the same effect as invoking the FindBusiness method of the UDDI Inquiry Web service with the following request:

 <find_business generic="1.0" xmlns="urn:uddi-org:api">         <name>Microsoft</name> </find_business> 

The result of the FindBusiness method is another XML document that contains detailed business information about Microsoft:

 <businessList generic="1.0"     operator="Microsoft Corporation"     truncated="false"     xmlns="urn:uddi-org:api">     <businessInfos>         <businessInfo businessKey="0076B468-EB27-42E5-AC09-9955CFF462A3">             <name>Microsoft Corporation</name>             <description xml:lang="en">                 Empowering people through great software -                 any time, any place and on any device is Microsoft's                 vision. As the worldwide leader in software for personal                 and business computing, we strive to produce innovative                 products and services that meet our customer's             </description>             <serviceInfos>                 <serviceInfo                     businessKey="0076B468-EB27-42E5-AC09-9955CFF462A3"                     serviceKey="1FFE1F71-2AF3-45FB-B788-09AF7FF151A4">                     <name>Web services for smart searching</name>                 </serviceInfo>                 <serviceInfo                     businessKey="0076B468-EB27-42E5-AC09-9955CFF462A3"                     serviceKey="8BF2F51F-8ED4-43FE-B665-38D8205D1333">                     <name>Electronic Business Integration Services</name>                 </serviceInfo>                 <serviceInfo                     businessKey="0076B468-EB27-42E5-AC09-9955CFF462A3"                     serviceKey="611C5867-384E-4FFD-B49C-28F93A7B4F9B">                     <name>Volume Licensing Select Program</name>                 </serviceInfo>                 <serviceInfo                     businessKey="0076B468-EB27-42E5-AC09-9955CFF462A3"                     serviceKey="A8E4999A-21A3-47FA-802E-EE50A88B266F">                     <name>UDDI Web Sites</name>                 </serviceInfo>             </serviceInfos>         </businessInfo>     </businessInfos> </businessList> 

The returned XML message provides useful information, such as a unique UDDI identifier for retrieving additional information, a business description, and a list of offered services. Any SOAP-enabled software or device can browse the UDDI registry for a specific service and then dynamically bind to the service to access the desired information or services.

Validating Web Service Accessibility

As mentioned, Web services are intended for interoperability with applications and devices existing on multiple operating platforms. To ensure a successful Web service deployment and to minimize customer frustration, it is important to test newly developed services with validation tools that check the structure of a Web service's related documents, such as WSDL and SOAP messages. Many tools are emerging that validate Web service documents:

http://www.gotdotnet.com/services/wsdl/wsdlverify.asmx?op=ValidateWSDL

The WsdlVerify Web service validates WSDL documents to ensure that they are well formed and contain all the necessary information to bind to a Web service. The previous URL points to the test page shown in Figure 9-12. Simply enter the URL of your hosted Web service to determine if it is valid. In most cases, WSDL documents generated by Visual Studio .NET do not need customization and in turn do not need validation. However, it is always useful to check.

click to expand
Figure 9-12: The WsdlVerify utility Web service



Developing. NET Enterprise Applications
Developing .NET Enterprise Applications
ISBN: 1590590465
EAN: 2147483647
Year: 2005
Pages: 119

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