8.3 Implementing Multiple Interfaces
The next logical step is to implement multiple interfaces on the same Web service. You do this by applying multiple WebServiceBinding attributes to the class implementing the Web service. On each Web method you set the SoapDocumentService or SoapRpcService Binding property to the name of the binding that contains this method. Taking the SupplierIface1 class in Listing 8.1, you might want to factor out its methods into two interfaces: IOrderMgmt and IQuoteMgmt. Listing 8.6 shows the code used to achieve this.
Listing 8.6 Defining multiple bindings (interfaces) (VBWSBook\Chapter8\Supplier2.asmx.vb)
<WebServiceBinding( _ Name:="IOrderMgmt", _ [Namespace]:="http://LearnXmlWS.com/Supplier"), _ WebServiceBinding( _ Name:="IQuoteMgmt", _ [Namespace]:="http://LearnXmlWS.com/Supplier"), _ WebService([Namespace]:="http://LearnXmlWS.com/Supplier")> _ Public Class SupplierIface2 Inherits System.Web.Services.WebService <WebMethod( _ Description:= _ "Places the order then returns the new order id"), _ SoapDocumentMethod(Binding:="IOrderMgmt")> _ Public Function PlaceOrder( _ ByVal newOrder As Order) As String 'returns a new order id End Function <WebMethod(), _ SoapDocumentMethod(Binding:="IOrderMgmt")> _ Public Function CheckStatus( _ ByVal OrderId As String) As OrderInfo 'returns an orderinfo structure End Function <WebMethod(), _ SoapDocumentMethod(Binding:="IQuoteMgmt")> _ Public Function GetPriceQuote( _ ByVal newOrder As Order) As QuoteInfo() 'returns an orderinfo structure End Function End Class
Note that there are two bindings with different namesboth in the same namespace. Also, GetPriceQuote is now part of the IQuoteMgmt binding.
Listing 8.7 shows the bindings defined in the resulting WSDL document.
Listing 8.7 The resulting WSDL document with two bindings (VBWSBook\Chapter8\MultiInterface.wsdl)
<binding name="IQuoteMgmt" type="s0:IQuoteMgmt"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" /> <operation name="GetPriceQuote"> <soap:operation soapAction="http://LearnXmlWS.com/Supplier/GetPriceQuote" style="document" /> <input> <soap:body use="literal" /> </input> <output> <soap:body use="literal" /> </output> </operation> </binding> <binding name="IOrderMgmt" type="s0:IOrderMgmt"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" /> <operation name="PlaceOrder"> <soap:operation soapAction="http://LearnXmlWS.com/Supplier/PlaceOrder" style="document" /> <input> <soap:body use="literal" /> </input> <output> <soap:body use="literal" /> </output> </operation> <operation name="CheckStatus"> <soap:operation soapAction="http://LearnXmlWS.com/Supplier/CheckStatus" style="document" /> <input> <soap:body use="literal" /> </input> <output> <soap:body use="literal" /> </output> </operation> </binding>
To implement these interfaces you run wsdl.exe with the /server parameter just as you did for the single interface case. However, the output this time is different: You get one file that contains two classesone for each binding. The first class you get, IQuoteMgmt, has one method called GetPriceQuote. The second class, IOrderMgmt, has two methods called PlaceOrder and CheckStatus. You can add this file to your Web service project and create classes that inherit from each of IQuoteMgmt and IOrderMgmt, and then start implementing each interface's methods. For example, Listing 8.8 shows a Web service that implements IQuoteMgmt.
Listing 8.8 An example Web service that implements IQuoteMgmt (VBWSBook\Chapter8\InterfaceImpl\QuoteMgmtImpl.asmx.vb)
Imports System.Web.Services Imports System.Web.Services.Protocols <WebServiceBinding( _ Name:="IQuoteMgmt", _ Namespace:="http://LearnXmlWS.com/Supplier", _ Location:= _ "http://vbwsserver/vbwsbook/chapter8/MultiInterface.wsdl"), _ WebService(Namespace:="http://tempuri.org/")> _ Public Class QuoteMgmtImpl Inherits MultiIface1.IQuoteMgmt <WebMethodAttribute(), _ SoapDocumentMethodAttribute( _ "http://LearnXmlWS.com/Supplier/GetPriceQuote", _ RequestNamespace:="http://LearnXmlWS.com/Supplier", _ ResponseNamespace:="http://LearnXmlWS.com/Supplier", _ Use:=Description.SoapBindingUse.Literal, _ ParameterStyle:=SoapParameterStyle.Wrapped, _ Binding:="IQuoteMgmt")> _ Public Overrides Function GetPriceQuote( _ ByVal newOrder As InterfaceImpl.MultiIface1.Order) _ As InterfaceImpl.MultiIface1.QuoteInfo() End Function End Class
Since .NET supports single inheritance, a class cannot inherit from more than one base class. This means you cannot create a Web service that inherits from both classes generated by wsdl.exe (the classes IQuoteMgmt and IOrderMgmt). You will end up with a Web service class for each binding you want to implement.
This is not exactly what comes to mind when I think of multiple interfaces. Ideally, we can have one Web service class that implements both IQuoteMgmt and IOrderMgt. While it's possible to achieve this, you can't do it by inheriting from abstract classes generated by wsdl.exe. Instead, you must create a Web service class, and then manually specify the bindings and the methods. The process is almost identical to the single-interface implementation case except you are not overriding any base class methods. The steps for implementing multiple interfaces on a single Web service class are:
Create a Web service.
Add a WebServiceBinding attribute to the Web service class for each interface you want to implement. Specify the binding's name, namespace, and location (the URL of a WSDL document where the binding is defined).
Create WebMethods on this Web service that correspond to the operations defined in each binding. You can get some help from wsdl.exe by running it with the /server flag then copying the abstract method definitions it creates and pasting them into your Web service. If you do this, be sure to remove the MustOverride keyword from those methods.
Specify the binding name for each Web method. This name must match one of the binding names defined by SoapServiceBinding attributes on the Web service class.
Listing 8.9 shows an example Web service class that implements both IQuoteMgmt and IOrderMgmt.
Listing 8.9 A single Web service class that implements both IQuoteMgmt and IOrderMgmt interfaces (VBWSBook\Chapter8\InterfaceImplMultipleInterfaceImpl.asmx.vb)
Imports System.Web.Services Imports System.Web.Services.Protocols <WebService(Namespace:="http://tempuri.org/"), _ WebServiceBindingAttribute(Name:="IQuoteMgmt", _ [Namespace]:="http://LearnXmlWS.com/Supplier", _ Location:= _ "http://vbwsserver/vbwsbook/chapter8/MultiInterface.wsdl"), _ WebServiceBindingAttribute(Name:="IOrderMgmt", _ [Namespace]:="http://LearnXmlWS.com/Supplier", _ Location:= _ "http://vbwsserver/vbwsbook/chapter8/MultiInterface.wsdl")> _ Public Class MultipleInterfaceImpl Inherits WebService <WebMethodAttribute(), _ SoapDocumentMethodAttribute( _ "http://LearnXmlWS.com/Supplier/GetPriceQuote", _ RequestNamespace:="http://LearnXmlWS.com/Supplier", _ ResponseNamespace:="http://LearnXmlWS.com/Supplier", _ Use:=Description.SoapBindingUse.Literal, _ ParameterStyle:=SoapParameterStyle.Wrapped, _ Binding:="IQuoteMgmt")> _ Public Function GetPriceQuote( _ ByVal newOrder _ As InterfaceImpl.MultiIface1.Order) _ As InterfaceImpl.MultiIface1.QuoteInfo() End Function <WebMethodAttribute(), _ SoapDocumentMethodAttribute( _ "http://LearnXmlWS.com/Supplier/PlaceOrder", _ RequestNamespace:="http://LearnXmlWS.com/Supplier", _ ResponseNamespace:="http://LearnXmlWS.com/Supplier", _ Use:=Description.SoapBindingUse.Literal, _ ParameterStyle:=SoapParameterStyle.Wrapped, _ Binding:="IOrderMgmt")> _ Public Function PlaceOrder( _ ByVal newOrder As InterfaceImpl.MultiIface1.Order) _ As String End Function <WebMethodAttribute(), _ SoapDocumentMethodAttribute( _ "http://LearnXmlWS.com/Supplier/CheckStatus", _ RequestNamespace:="http://LearnXmlWS.com/Supplier", _ ResponseNamespace:="http://LearnXmlWS.com/Supplier", _ Use:=Description.SoapBindingUse.Literal, _ ParameterStyle:=SoapParameterStyle.Wrapped, _ Binding:="IOrderMgmt")> _ Public Function CheckStatus(ByVal OrderId As String) _ As InterfaceImpl.MultiIface1.OrderInfo End Function End Class
The Web service class in Listing 8.9 has two WebServiceBinding attributes for IQuoteMgmt and ISupplierMgmt. Inside the class, you'll see the GetPriceQuote Web method that belongs to the IQuoteMgmt interface. You'll also see the IOrderMgmt interface methods: PlaceOrder and CheckStatus. Listing 8.10 shows the resulting WSDL.
Listing 8.10 The WSDL for the service in Listing 8.9
<?xml version="1.0" encoding="utf-8"?> <definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:i0="http://LearnXmlWS.com/Supplier" xmlns:tns="http://tempuri.org/" targetNamespace="http://tempuri.org/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <import namespace="http://LearnXmlWS.com/Supplier" location= "http://vbwsserver/vbwsbook/chapter8/MultiInterface.wsdl" /> <types /> <service name="MultipleInterfaceImpl"> <port name="IOrderMgmt" binding="i0:IOrderMgmt"> <soap:address location="http://vbwsserver/vbwsbook/chapter8/_ InterfaceImpl/MultipleInterfaceImpl.asmx" /> </port> <port name="IQuoteMgmt" binding="i0:IQuoteMgmt"> <soap:address location="http://vbwsserver/vbwsbook/chapter8/_ InterfaceImpl/MultipleInterfaceImpl.asmx" /> </port> </service> </definitions>
The most interesting feature of the WSDL in Listing 8.10 is the presence of two <port> elements inside the <service> element, indicating that the service implements two different interfaces.