Solution


The technique presented next requires both the web service provider and the client to write their code in a slightly different way, in order to make use of interface-based web services. To create an interface-based web service, first expose the web service interface definition. For simplicity's sake, assume the service provider is responsible for both defining and implementing the interface. There is an easy way for the client or any other third party to expose the web service interface definition and have anybody implement it, but that requires one or two additional steps (described later).

Service-Side Steps

In Visual Studio 2005, select File New Web Site... to bring up the New Web Site dialog box. Select ASP.NET Web Service and name it CalculationServices. Visual Studio 2005 will create a skeletal web service called Service. You have no use for it, so remove the file Service.cs from the App_Code folder. To add the web service interface, right-click on the project, then select Add New Item... from the context menu to bring up the Add New Item dialog. Select Web Service in the dialog, and name it ICalculator. Make sure that the "Place code in separate file" checkbox is checked, and click Add.

Open the ICalculator.cs file in the App_Code folder and change the ICalculator type definition from class to interface. Remove the constructor and the HelloWorld( ) method and the derivation from WebService. You can also remove the public interface accessibility modifier. Change the WebServiceBinding attribute to read:

     [WebServiceBinding (Name = "ICalculator")]

Next, add the Add( ), Subtract( ), Divide( ), and Multiply( ) interface methods. Apply the WebMethod attribute to every method on the interface. The interface should now look like this:

     [WebServiceBinding (Name = ICalculator)]     interface ICalculator     {        [WebMethod(Description = "Adds two integers and returns the sum")]        int Add(int argument1,int argument2);        [WebMethod(Description = "Subtracts two integers and returns the result")]        int Subtract(int argument1,int argument2);        [WebMethod(Description = "Divides two integers and returns the result")]        int Divide(int argument1,int argument2);        [WebMethod(Description = "Multiplies two integers and returns the result")]        int Multiply(int argument1,int argument2);     }

The WebServiceBinding attribute designates the ICalculator interface as an interface that defines a web service contract, but does not expose it as a web service. Other classes that have access to the ICalculator metadata definition can now implement (or bind to) the service contract definition.

Next, implement the ICalculator interface on the web service classes. Doing so is like implementing any other interface in .NET: the class should derive from the interface and provide the implementation for its methods. For example, use the Add New Item dialog to add two web services, called SimpleCalculator and ScientificCalculator. Clean up the wizard-generated code as described earlier. Add to the classes a derivation from the ICalculator interface, and implement it.

Add the WebService attribute for specifying the namespace and the description. Example A-4 shows the two implementations of ICalculator. Note that the compiler insists that the service provider implement all the methods defined by the interface.

Example A-4. Two different web services' implementations of the ICalculator interface
 [WebService(Namespace="http://CalculationServices",             Description = "The SimpleCalculator web service implements ICalculator.                            It provides the four basic arithmetic operations.")] class SimpleCalculator : ICalculator {    public int Add(int argument1,int argument2)    {       return argument1 + argument2;    }    //Other ICalculator methods } [WebService(Namespace="http://CalculationServices",             Description = "The ScientificCalculator web service implements             ICalculator. It provides the four basic arithmetic operations.")] class ScientificCalculator : ICalculator {    public int Add(int argument1,int argument2)    {       return argument1 + argument2;    }    //Other ICalculator methods }

A class can implement multiple interfaces decorated with the WebServiceBinding attribute, each corresponding to a different service contract.


Now you need to expose the interface as a web interface. However, you cannot expose an interface as a web service. To overcome this hurdle, you need to provide an interface shim zan abstract class that exposes to the world what looks like a pure interface definition. Add to the web service project a class called ICalculatorShim, and place it in the file ICalculatorShim.cs. Define the class as abstract, and have it derive from ICalculator. Provide only abstract methods as interface implementation:

     [WebService(Name = "ICalculator",Namespace="http://CalculationServices",                 Description = "This web service is only the definition of the                                interface. You cannot invoke method calls on it.")]     abstract class ICalculatorShim : ICalculator     {        public abstract int Add(int argument1,int argument2);        public abstract int Subtract(int argument1,int argument2);        public abstract int Divide(int argument1,int argument2);        public abstract int Multiply(int argument1,int argument2);     }

Because it derives from ICalculator, the compiler enforces that the shim class exposes all the methods defined by the interface. Use the WebServiceAttribute attribute to provide the namespace and a description. Most importantly, set the Name property of WebServiceAttribute to ICalculator. Doing so exposes the service definition as ICalculator instead of ICalculatorShim.

Finally, modify the ICalculator.asmx file so that it will load the ICalculatorShim class from the correct file:

     <%@ WebService Language="C#" CodeBehind="~/Code/ICalculatorShim.cs"         docEmphStrong">Shim"%>

To verify that all is well so far, set the ICalculator.asmx file as the start page and run the project. The auto-generated browser test page presents the ICalculator interface definition (see Figure A-1).

Figure A-1. The ICalculator auto-generated test page


If you try to invoke any of the methods you will get an error, because there is no implementation behind the service.

Client-Side Steps

The client needs to have the interface definition so that it can program against it. The client can obtain that definition in two ways. The first uses the WSDL.exe command-line utility. Using the /serverInterface switch, you can instruct WSDL.exe to generate an interface definition matching that of the web service contract. Assuming the interface definition resides at http://localhost/CalculationServices.com/ICalculator.asmx, run the utility with this command line:

     WSDL.exe /serverInterface http://localhost/CalculationServices.com/ICalculator.asmx              /out:ICalculator.cs

WSDL.exe will generate a file called ICalculator.cs containing the definition of an interface called IICalculator:

     [WebServiceBinding (Name = "ICalculator",                        Namespace="http://CalculationServices/")]     public partial interface I ICalculator     {        [WebMethod]        [SoapDocumentMethod("http://CalculationServices/Add",...]        int Add(int argument1,int argument2);        //Other IICalculatorSoap methods     }

Add the ICalculator.cs source file to the client project. The IICalculator definition in ICalculator.cs is oriented toward the interface implementer, not the service consumer. As such, it contains service-side attributes, such as WebService and WebMethod. You can safely remove these attributes, or you can keep themthey make no difference on the client side. Rename IICalculatorSoap to ICalculator.

Using the WSDL.exe command-line utility with the /serverInterface switch is how a service provider imports an interface defined by another party.


The second way a client can import the interface definition is by adding a web reference to the ICalculator web service. After adding the reference, the client manually extracts the interface methods from the proxy class. To do so, point the Add Web Reference wizard to the site containing the interface definition. This generates a proxy class called ICalculator, which exposes the original ICalculator's methods as well as the methods used for asynchronous method invocation, as described in Chapter 8. Each of these methods is implemented to forward calls to the web service. Of course, for an interface definition, you need only method definitions. Remove all the interface method bodies and the other methods completely, including the constructor. Remove the SoapHttpClientProtocol base class and the public modifier on the methods, and then remove all class and method attributes. Finally, change the ICalculator definition from class to interface. The client side should now have the original interface definition.

Regardless of how the client imports the interface definition, it will need to consume the web services that actually implement the interface. Bring up the Add Web Reference wizard and point the wizard to where the implementations reside. Visual Studio 2005 will generate proxy classes for the interface implementations (SimpleCalculator and ScientificCalculator, in this case). These machine-generated proxy classes are the default proxy classes; they will look just like Example A-2 and will not refer to ICalculator. It's up to the client to provide polymorphism with ICalculator by adding a derivation from the interface:

     public partial class ScientificCalculator : ICalculator     {}     public partial class SimpleCalculator : ICalculator     {}

Because the proxy classes are marked as partial classes, you can even add the interface derivation in a separate file and keep updating the proxy class files as needed.

Finally, the client can write interface-based web-services-polymorphic code, as in Example A-3. Note that the only difference between the two proxy classes is in the URL of the web service implementing the ICalculator interface. This leads to an interesting observation: in the web services world, from the client's perspective, the location of the service (i.e., the URL) is the object's type.

Note also that the technique described in this appendix works with other web service protocols besides SOAPnamely, HTTP-POST. Using the WSDL.exe utility, you can generate proxy classes that use these protocols and add the derivation from the web service interface.



Programming. NET Components
Programming .NET Components, 2nd Edition
ISBN: 0596102070
EAN: 2147483647
Year: 2003
Pages: 145
Authors: Juval Lowy

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