SOAP Encoding Styles

Interface Inheritance

As I mentioned at the beginning of the chapter, the Securities Web service is intended to be consumed by portals such as MSN and Yahoo! Come to find out that other brokerage companies have approached MSN as well. In an effort to accommodate the numerous requests, MSN has defined a standard interface in which it will communicate with the various online brokerage firms.

Interface-based programming has been popularized by technologies such as COM, CORBA, and Java. Within the .NET platform, interfaces continue to play an important role. They facilitate treating different objects in a polymorphic fashion without the overhead and complexity of implementation inheritance.

An interface defines a contract by which classes that inherit a particular interface must support all the methods defined by the interface. Code that can interact with a particular interface can consume any object that exposes that interface. For example, the IClonable interface can be exposed by an object that knows how to clone itself. Code written against the IClonable interface will be able to clone any object that exposes the interface.

In the case of MSN, it would not be ideal to write custom client code to interface with every single securities-related Web service. Instead, MSN can define a standard interface that all the securities-related Web services must comply with.

The first task for MSN is to create an abstract interface for the Securities Web service. As you learned in the previous chapter, a Web service interface is defined within a WSDL document. A transport-specific interface definition is represented by a binding definition, while a transport-agnostic interface definition is represented by a port type definition.

The easiest way to generate a WSDL document that describes the interface is to have ASP.NET automatically generate the WSDL for you. The following example creates a Web service that defines an abstract class:

<%@ WebService Language="c#"  %> using System; using System.Web.Services; using System.Web.Services.Protocols; namespace MSN {     [WebService(Namespace="http://msn.com/Securities")]     [SoapRpcService]     public abstract class Securities : WebService     {         [WebMethod]         public abstract double InstantQuote(string symbol);     } }

The preceding code defines an interface for the Securities Web service. Unfortunately, the abstract keyword is not recognized by the ASP.NET platform, so the code will define a full WSDL document, not just the interfaces.

One way to overcome this problem is to save the WSDL that is generated by the ASP.NET runtime with its service definitions removed. Without the service definitions, a client will have no way of locating the endpoints, which makes the interface definitions abstract. Here is the WSDL document with its service definitions removed:

<?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:tns="http://msn.com/Securities"  targetNamespace="http://msn.com/Securities"  xmlns="http://schemas.xmlsoap.org/wsdl/">   <types />   <message name="InstantQuoteSoapIn">     <part name="symbol" type="s:string" />     <part name="count" type="s:int" />   </message>   <message name="InstantQuoteSoapOut">     <part name="InstantQuoteResult" type="s:double" />   </message>   <portType name="SecuritiesSoap">     <operation name="InstantQuote">       <input message="tns:InstantQuoteSoapIn" />       <output message="tns:InstantQuoteSoapOut" />     </operation>   </portType>   <binding name="SecuritiesSoap" type="tns:SecuritiesSoap">     <soap:binding      transport="http://schemas.xmlsoap.org/soap/     http" style="rpc" />     <operation name="InstantQuote">       <soap:operation        soapAction="http://msn.com/Securities/       InstantQuote" style="rpc" />       <input>         <soap:body use="encoded" namespace="http://msn.com/Securities"          encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />       </input>       <output>         <soap:body use="encoded" namespace="http://msn.com/Securities"          encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />       </output>     </operation>   </binding> </definitions>

In addition to removing the service definitions, I also remove any definitions not directly related to the SOAP binding. I will readdress this issue in a moment when I discuss some of the limitations of the ASP.NET support for interface inheritance.

A Web service can inherit an interface by referencing a port type or a binding that is defined by another Web service. ASP.NET does not provide a mechanism for providing protocol-agnostic interface inheritance. For example, you cannot inherit an interface from a Web service that is exposed only via SMTP. To do this, you would have to hand-roll the WSDL used to describe the service so that it references the port type defined within another namespace. You would also need to disable the WSDL document that is automatically generated by ASP.NET. (See the “Web Service Documentation” section earlier in the chapter.)

ASP.NET does provide a mechanism for facilitating transport-specific interface inheritance. You use the WebServiceBinding attribute to reference a binding defined within another namespace. You use the Binding property of the SoapDocumentMethod or SoapRpcMethod attribute to reference the binding definition referenced by the WebServiceBinding attribute.

Next I modify the definition of the Securities Web service to inherit the interface defined within the MSN namespace. I do so by referencing the SecuritiesSoap binding definition. Suppose the preceding WSDL document is located at http://msn.com/Securities.wsdl. The following code defines the Securities Web service provided by www.woodgrovebank.com:

using System; using System.Web.Services; using System.Web.Services.Protocols; namespace BrokerageFirm {     [SoapRpcService]     [WebServiceBinding("SecuritiesSoap",      "http://msn.com/Securities", "http://msn.com/Securities.wsdl")]     public class Securities : WebService     {

I reference the SecuritiesSoap binding definition using the WebServiceBinding attribute. The three parameters I pass to the attribute's constructor are the name of the referenced binding definition, the namespace containing the definition, and the location of the WSDL document containing the definition.

If the binding definition is referenced within the Web method, the ASP.NET runtime will add a reference to the WSDL namespace that contains the binding. The ASP.NET runtime will also add an import element to the autogenerated WSDL document. Finally, the ASP.NET runtime will add a port within the service definition that is associated with the referenced binding definition, as shown here:

        [WebMethod]         [SoapRpcMethod(Binding="SecuritiesSoap")]         public double InstantQuote(string symbol)         {             double price = 0;             // Implementation...             return price;         }     } }

I use the Binding property of SoapRpcMethod to associate the Web method with the binding definition. The value of the binding property must match the name assigned to a WebServiceBinding attribute defined at the class level; otherwise, a run-time exception will occur.

Using the WebServiceBinding attribute to facilitate interface inheritance has some limitations. First, you can reference only SOAP binding definitions. There is also no tool support for referencing external binding definitions. Developers must take it upon themselves to create Web methods that match the referenced binding definition. Finally, there is no validation either at compile time or at run time to ensure that the Web service implements all the methods exposed by the inherited interface.

To ensure that the Web service supports all the methods of the inherited interface, you can use the WSDL.exe tool to generate an abstract class representing the Web service. You can then add the resulting code to your project and derive from the abstract class instead of the WebService class. The following example creates the BaseSecurities.cs file that contains an abstract class definition for the base Web service:

wsdl /server /out:BaseSecurities.cs http://msn.com/Securities.wsdl

Once BaseSecurities.cs has been created and added to my project, I can derive the Web service as follows:

using System; using System.Web.Services; using System.Web.Services.Protocols; namespace BrokerageFirm { [WebService(Description="This Web service provides services related to  securities.")] [SoapRpcService] [WebServiceBinding("SecuritiesSoap", "http://msn.com/Securities",      "http://msn.com/Securities.wsdl")]  public class Securities : MSN.Securities { // Implementation... } }

If the Securities class does not implement all the abstract methods defined within the MSN.Securities class, I will receive a compiler error.



Building XML Web Services for the Microsoft  .NET Platform
Building XML Web Services for the Microsoft .NET Platform
ISBN: 0735614067
EAN: 2147483647
Year: 2002
Pages: 94
Authors: Scott Short

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