Consuming Web Services

only for RuBoard

Now that you have seen how to create and expose a web service, this section looks at creating clients to consume these web services.

Web Service Description Language

At the time of writing, the WSDL specification (available at www.w3.org/TR/wsdl) is an acknowledged submission to W3C and is supported by industry leaders like Microsoft, IBM and Ariba. According to this specification, the official definition of Web Service Description Language (WSDL) states that, "WSDL is an XML format for describing network services as a set of endpoints operating on messages containing either document-oriented or procedure-oriented information." If you are familiar with the COM and CORBA component models, you can relate this to the Interface Description Language (IDL) file that describes the interfaces exposed by the components in a platform-neutral manner. Similar to IDL, a WSDL file defines a contract between a client and a server (a web service, in this case).

SOAP messages do carry type information; therefore, SOAP allows for dynamic determination of type. But without WSDL, it's impossible to call a function correctly unless the client application developer knows the name and the parameters in advance by reading the documentation or by examining wire messages. WSDL enables us to eliminate the human intervention required for acquiring the knowledge of the method names and the parameters, as it is possible to automate the generation of proxies for web services. Moreover, this happens in a truly language- and platform-independent way because WSDL uses XML syntax to describe the web service.

The SOAP Toolkit 2.0 provides a WSDL generation wizard that takes the COM component as the input and generates a WSDL file for you. A small drawback with this is that, if anything changes in the method signatures in the component, you must redo the process of the WSDL file generation. In an ASP.NET web service, you avoid the task of generating the WSDL file from the wizard. This is because when you simply append ?WSDL to the .asmx document URL, you get a WSDL file. Because this is generated dynamically by inspecting the methods marked with the WebMethod attribute in the .asmx file for every request, this is guaranteed to reflect the latest modifications in the .asmx file. Figure 11.4 shows the WSDL generated for the Calculator web service.

Figure 11.4. The WSDL for the Calculator web service.
graphics/11fig04.gif

The generated WSDL in Figure 11.4 describes the HTTP-GET , HTTP-POST , and SOAP protocols. You must look at the part of the WSDL document that describes the bindings for the SOAP protocol and try to understand the document structure. Listing 11.3 shows the WSDL using SOAP.

Listing 11.3 The WSDL File for the Calculator Web Service
 <?xml version="1.0" encoding="utf-8" ?>  <definitions xmlns:s="http://www.w3.org/2001/XMLSchema"                  xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"                  xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"                  xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"                  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"                  xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"                  xmlns:s0="http://tempuri.org/"targetNamespace="http://tempuri.org/"                  xmlns="http://schemas.xmlsoap.org/wsdl/">       <types>            <s:schema attributeFormDefault="qualified"                        elementFormDefault="qualified"                        targetNamespace="http://tempuri.org/">                 <s:element name="Add">                      <s:complexType>                           <s:sequence>                                <s:element minOccurs="1" maxOccurs="1"                                             name="a" type="s:int" />                                <s:element minOccurs="1" maxOccurs="1"                                             name="b" type="s:int" />                            </s:sequence>                        </s:complexType>                 </s:element>                 <s:element name="AddResponse">                      <s:complexType>                           <s:sequence>                                <s:element minOccurs="1" maxOccurs="1"                                             name="AddResult" type="s:int" />                           </s:sequence>                      </s:complexType>                 </s:element>                 <s:element name="Subtract">                      <s:complexType>                           <s:sequence>                                <s:element minOccurs="1" maxOccurs="1"                                             name="a" type="s:int" />                                <s:element minOccurs="1" maxOccurs="1"                                             name="b" type="s:int" />                            </s:sequence>                      </s:complexType>                  </s:element>                  <s:element name="SubtractResponse">                      <s:complexType>                            <s:sequence>                                <s:element minOccurs="1" maxOccurs="1"                                          name="SubtractResult" type="s:int" />                            </s:sequence>                       </s:complexType>                 </s:element>                 <s:element name="int" type="s:int" />            </s:schema>       </types>       <message name="AddSoapIn">            <part name="parameters" element="s0:Add" />       </message>       <message name="AddSoapOut">           <part name="parameters" element="s0:AddResponse" />       </message>       <message name="SubtractSoapIn">             <part name="parameters" element="s0:Subtract" />       </message>       <message name="SubtractSoapOut">            <part name="parameters" element="s0:SubtractResponse" />       </message>       <portType name="CalculatorSoap">            <operation name="Add">                 <input message="s0:AddSoapIn" />                 <output message="s0:AddSoapOut" />            </operation>            <operation name="Subtract">                 <input message="s0:SubtractSoapIn" />                 <output message="s0:SubtractSoapOut" />            </operation>       </portType>       <binding name="CalculatorSoap" type="s0:CalculatorSoap">            <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" graphics/ccc.gif />            <operation name="Add">                 <soap:operation soapAction="http://tempuri.org/Add" style="document" />                 <input>                      <soap:body use="literal" />                 </input>                 <output>                      <soap:body use="literal" />                 </output>            </operation>            <operation name="Subtract">                 <soap:operation soapAction="http://tempuri.org/Subtract" style="document" / graphics/ccc.gif >                 <input>                     <soap:body use="literal" />                 </input>                 <output>                     <soap:body use="literal" />                 </output>            </operation>       </binding>       <service name="Calculator">            <port name="CalculatorSoap" binding="s0:CalculatorSoap">                 <soap:address  location="http://localhost/WebServices/Calculator/Calculator.asmx" />            </port>       </service>  </definitions> 

Five major sections are in the WSDL document, which can be categorized into two groups. The top group is comprised of abstract definitions, and the bottom group consists of concrete descriptions. The abstract sections define SOAP messages in a platform- and language-independent manner; they do not contain any machine- nor language-specific elements. This helps define a set of services that several diverse websites can implement. Site-specific matters, such as serialization, are then relegated to the bottom sections, which contain concrete descriptions.

Abstract Definitions

The following abstract definitions are found in the WSDL file:

  • Types ” The <types> element contains the parameters names and data type definitions for parameters and the return types of web service methods. This type definition is based on an XSD schema. This schema is referenced from the Messages section of the document.

  • Messages ” If you consider operations as functions, then a <message> element defines the parameters to that function. Each <part> child element in the <message> element corresponds to a parameter. Input parameters are defined in a single <message> element, separate from output parameters, which are in their own <message> element. Parameters that are both input and output have their corresponding <part> elements in both input and output <message> elements. The name of an output <message> element ends in Response , as in AddResponse , by convention. Each <part> element has name and type attributes, just as a function parameter has both a name and type.

  • PortTypes ” Refers to message definitions in a Messages section to describe function signatures (such as operation name, input parameters, and output pameters). Operation elements within a PortType define the syntax for calling all methods in the PortType . Each <portType> element groups together a number of related operations. In an <operation> element, there can be at most one <input> element, at most one <output> element, and at most one <fault> element. Each of these three elements has name and message attributes.

Concrete Descriptions

The following abstract definitions are found in the WSDL file:

  • Bindings ” The Binding section is where the protocol, serialization, and encoding on the wire corresponding to the operations defined in the portType element are fully specified. The style attribute in the <binding> element specifies the message serialization format as SOAP Section 5 RPC-style or document-style encoding. The <soap:operation> within the <operation> element specifies the value of the SOAPAction HTTP header. The <input> and <output> elements within the <operation> element specify how the input and output messages of the individual operation are encoded.

  • Services ” Specifies port address(es) of each binding. Therefore, a service is a set of <port> elements. Each <port> element associates a location with a <binding> in a one-to-one fashion. If more than one <port> element is associated with the same <binding> , the additional URL locations can be used as alternates. More than one <service> element can exist in a WSDL document.

Note

You can find the WSDL 1.1 Specification that has been submitted to the W3C as a Note at www.w3.org/TR/wsdl.


Creating a proxy Using Visual Studio .NET

For the development of the client of web services,Visual Studio .NET provides a new option to add a web reference to the web service. With this easy-to-use option, a proxy class is automatically generated. The Add Web Reference option is available from the Project menu or by right-clicking References in the Solution Explorer. Figure 11.5 shows a web reference being added in a Visual Studio .NET project.

Figure 11.5. Adding a web reference in a Visual Studio .NET project.
graphics/11fig05.gif

Figure 11.6 shows the Solution Explorer with the added web reference.

Figure 11.6. The Solution Explorer showing the added web reference.
graphics/11fig06.gif

Now that you have a proxy automatically generated, use it to build a client. You can design a user interface for the client, as shown in Figure 11.7.

Figure 11.7. Designing the user interface with the designer in Visual Studio .NET.
graphics/11fig07.gif

The following code for the Add and Subtract button click events shows the use of the proxy to access the Calculator web service:

 //Add  private void Button1_Click(object sender, System.EventArgs e)  { CalculatorService.Calculator calc = new CalculatorService.Calculator();  Label4.Text =  calc.Add(Int32.Parse(TextBox1.Text),Int32.Parse(TextBox2.Text)).ToString();  }  //Subtract  private void Button2_Click(object sender, System.EventArgs e)  { CalculatorService.Calculator calc = new CalculatorService.Calculator();  Label4.Text = calc.Subtract(Int32.Parse(TextBox1.Text),Int32.Parse graphics/ccc.gif (TextBox2.Text)).ToString();  } 

Figure 11.8 shows the result of clicking the Add button.

Figure 11.8. The web service client in action.
graphics/11fig08.gif

Creating a proxy Using the WSDL Tool

Running the WSDL tool with the following code creates a source file named Calculator.cs for the proxy object:

 wsdl /o:Calculator.cs  http://localhost/WebServices/Calculator/Calculator.asmx?WSDL 

Figure 11.9 shows the WSDL tool being used to create a proxy class.

Figure 11.9. Generating a source file using the WSDL tool.
graphics/11fig09.gif

For more information on all the options available for the WSDL tool refer to Chapter 4, "XML Tool Support in Visual Studio .NET."

Listing 11.4 shows the auto-generated proxy source created by the WSDL tool. Note that the proxy class generated by Visual Studio .NET has the same code as that's generated by the WSDL tool.

Listing 11.4 Auto-Generated proxy Source for the Calculator Web Service ( Calculator.cs )
 using System.Diagnostics;  using System.Xml.Serialization;  using System;  using System.Web.Services.Protocols;  using System.ComponentModel;  using System.Web.Services;  /// <remarks/>  [System.Diagnostics.DebuggerStepThroughAttribute()]  [System.ComponentModel.DesignerCategoryAttribute("code")]  [System.Web.Services.WebServiceBindingAttribute(Name="CalculatorSoap", Namespace="http:// graphics/ccc.gif tempuri.org/")]  public class Calculator :  System.Web.Services.Protocols.SoapHttpClientProtocol {     /// <remarks/>      public Calculator() {         this.Url = "http://localhost/WebServices/Calculator/Calculator.asmx";      }      /// <remarks/>  [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/Add", graphics/ccc.gif RequestNamespace="http://tempuri.org/",  ResponseNamespace="http://tempuri.org/",  Use=System.Web.Services.Description.SoapBindingUse.Literal,  ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]      public int Add(int a, int b) {         object[] results = this.Invoke("Add", new object[] {                     a,                      b});          return ((int)(results[0]));      }      /// <remarks/>      public System.IAsyncResult BeginAdd(int a, int b, System.AsyncCallback callback, graphics/ccc.gif object asyncState) {         return this.BeginInvoke("Add", new object[] {                     a,                      b}, callback, asyncState);      }      /// <remarks/>      public int EndAdd(System.IAsyncResult asyncResult) {         object[] results = this.EndInvoke(asyncResult);          return ((int)(results[0]));      }      /// <remarks/>  [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/Subtract", graphics/ccc.gif RequestNamespace="http://tempuri.org/",  ResponseNamespace="http://tempuri.org/",  Use=System.Web.Services.Description.SoapBindingUse.Literal,  ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]      public int Subtract(int a, int b) {         object[] results = this.Invoke("Subtract", new object[] {                     a,                      b});          return ((int)(results[0]));      }      /// <remarks/>      public System.IAsyncResult BeginSubtract(int a, int b, System.AsyncCallback callback, graphics/ccc.gif object asyncState) {         return this.BeginInvoke("Subtract", new object[] {                     a,                      b}, callback, asyncState);      }      /// <remarks/>      public int EndSubtract(System.IAsyncResult asyncResult) {         object[] results = this.EndInvoke(asyncResult);          return ((int)(results[0]));      }  } 

The proxy class inherits from the System.Web.Services.Protocols. SoapHttpClientProtocol base class. The generated proxy class and the SoapHttpClientProtocol class wrap up the details of sending and receiving SOAP requests and responses to the web service, thereby making the client developer's job trivial. The client developer does not need to understand the subtleties of the SOAP message structure unless he or she wants low-level control over SOAP messages being serialized and deserialized.

Table 11.3 contains some useful public properties of the proxy object that it inherits from the SoapHttpClientProtocol class. The clients can make use of these properties to alter the default behavior of the generated proxy classes.

Table 11.3. Public Properties of the proxy Object

Property

Description

AllowAutoRedirect

Gets or sets whether the client automatically follows server redirections. If a client sends authentication information, such as a username and password, you do not want to enable the server to redirect because it might compromise security.

ClientCertificates

Gets the collection of client certificates. This property allows a client to pass one or more client certificates, also known as Authenticode X.509 v.3 certificates, when calling an XML Web Service method. If the XML Web Service method is configured to use client certificates, a client certificate can be used as one mechanism for authenticating a client.

CookieContainer

Gets or sets the collection of cookies. If an XML Web Service method uses session state, a cookie is passed back in the response headers to the XML Web Service client that uniquely identifies the session for that XML Web Service client. In order for the XML Web Service client to receive that cookie, a new instance of CookieContainer must be created and assigned to the CookieContainer property before the XML Web Service method is called. This ensures that the cookie is properly included in subsequent requests.

Credentials

Gets or sets security credentials for web service client authentication. When using the Credentials property, an XML Web Service client must instantiate a class implementing ICredentials , such as NetworkCredential , and set the client credentials specific to the authentication mechanism. The NetworkCredential class can set authentication credentials by using the basic, digest, NTLM, and Kerberos authentication mechanisms.

PreAuthenticate

When PreAuthenticate is true, the WWW-authenticate header is sent with the first request if the authentication mechanism supports doing so. When PreAuthenticate is false, a request is made to the XML Web Service method without initially attempting to authenticate the user. If the XML Web Service allows anonymous access, the XML Web Service method is executed. If anonymous access is disallowed , a 401 HTTP return code is sent back to the client. In response, the WebClientProtocol class returns authentication credentials to the web server. If the client is authenticated and subsequently authorized to access the XML Web Service, the XML Web Service method is executed; otherwise , the client is denied access.

Proxy

Gets or sets proxy information for making an XML Web Service request through a firewall. Use the proxy property if a client needs to use different proxy settings than those in the system settings. You can use the WebProxy class to set the proxy settings because it implements IWebProxy .

Timeout

Indicates the time an XML Web Service client waits for a synchronous XML Web Service request to complete (in milliseconds ).

Setting the Timeout property to Timeout.Infinite indicates that the request doesn't time out. Although an XML Web Service client can set the Timeout property to not time out, the web server can still cause the request to time out on the server side.

Url

Gets or sets the base URL of the XML Web Service that the client is requesting.

The Url property can be changed to refer to any XML Web Service that implements the same service description from which the proxy class was generated.

UserAgent

Gets or sets the value for the user agent header that's sent with each request.

only for RuBoard


XML and ASP. NET
XML and ASP.NET
ISBN: B000H2MXOM
EAN: N/A
Year: 2005
Pages: 184

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