Home > Articles

  • Print
  • + Share This
This chapter is from the book

8.5 Programming Against Interfaces

The previous section showed you how to define and implement interfaces. This section completes the picture by showing you how to code clients against those interfaces.

8.5.1 Generating Proxies from Interfaces

On the client side, a Web service proxy exposes the set of methods that reflects the binding's operations. As far as the client is concerned, this set of methods is considered the Web service's interface.

When you add a Web reference to an interface-only WSDL document, Visual Studio .NET recognizes an interface-only WSDL and generates the proxy class for you (beta versions didn't do this). Since the WSDL document doesn't contain a <service> element, the generated proxy class will not have a Web service URL in its constructor. You can also use wsdl.exe to generate the proxy class:

wsdl.exe /l:VB /out:MyClass.vb SingleInterface.wsdl

Listing 8.13 shows two example proxy classes one for IOrderMgmt and one for IQuoteMgmt. These proxies were generated using wsdl.exe.

Listing 8.13 Proxy classes generated based on IOrderMgmt and IQuoteMgmt interface definitions (VBWSClientCode\Chapter8\Interfaces\InterfaceClientSupplier3.vb)

<WebServiceBindingAttribute( _
    Name:="IOrderMgmt", _
    [Namespace]:="http://LearnXmlWS.com/OrderMgmt")> _
Public Class COrderMgmt
    Inherits SoapHttpClientProtocol

    Public Sub New()
        MyBase.New()
    End Sub

    <SoapDocumentMethod( _
        "http://LearnXmlWS.com/Supplier/PlaceOrder", _
        RequestNamespace:="http://LearnXmlWS.com/Supplier", _
        ResponseNamespace:="http://LearnXmlWS.com/Supplier")> _
    Public Function PlaceOrder(ByVal newOrder As Order) As String
        Dim results() As Object = Me.Invoke("PlaceOrder", _
                            New Object() {newOrder})
        Return CType(results(0), String)
    End Function


    <SoapDocumentMethod( _
     "http://LearnXmlWS.com/Supplier/CheckStatus", _
     RequestNamespace:="http://LearnXmlWS.com/Supplier", _
     ResponseNamespace:="http://LearnXmlWS.com/Supplier")> _
     Public Function CheckStatus( _ 
                      ByVal OrderId As String) As OrderInfo
        Dim results() As Object = Me.Invoke("CheckStatus", _
                            New Object() {OrderId})
        Return CType(results(0), OrderInfo)
    End Function

End Class

<WebServiceBinding( _
    Name:="IQuoteMgmt", _
    [Namespace]:="http://LearnXmlWS.com/QuoteMgmt")> _
Public Class CQuoteMgmt
    Inherits SoapHttpClientProtocol

    <SoapDocumentMethod( _
        "http://LearnXmlWS.com/Supplier/GetPriceQuote", _
        RequestNamespace:="http://LearnXmlWS.com/Supplier", _
        ResponseNamespace:="http://LearnXmlWS.com/Supplier")> _
    Public Function GetPriceQuote( _ 
                    ByVal newOrder As InterfaceClient.Order) _
                As InterfaceClient.QuoteInfo()
        Dim results() As Object = Me.Invoke("GetPriceQuote", _
                            New Object() {newOrder})
        Return CType(results(0), QuoteInfo())
    End Function
End Class

I specifically renamed the classes to begin with a "C" to make it clear that these are classes and not interfaces. The first class, COrderMgmt, represents the IOrderMgmt binding as indicated by its WebServiceBinding attribute. The class inherits from SoapHttpClientProtocol and adds two methods, PlaceOrder and CheckStatus, each with a SoapDocumentMethod attribute that defines the request and response namespaces as defined in the WSDL. Similarly, the second class, CQuoteMgmt, represents the IQuoteMgmt binding. It also inherits from SoapHttpClientProtocol and adds a function called GetPriceQuote as defined in the WSDL.

The classes in Listing 8.13 are definitely good enough for the client to call the service based on the two interfaces IOrderMgmt and IQuoteMgmt. However, some developers might want to take it a step further and program against interfaces, instead of classes, on the client side.

Unfortunately, WebServiceBinding cannot be applied to interfaces. One way around this is to define manually two interfaces on the client side called IOrderMgmt and IQuoteMgmt as shown in Listing 8.14.

Listing 8.14 Defining interfaces on the client side and creating a class that implements these interfaces and forwards method calls to the Web service proxy classes (VBWSClientCode\Chapter8\Interfaces\InterfaceClientSupplier3.vb)

Interface IOrderMgmt
    Function PlaceOrder(ByVal newOrder As Order) As String
    Function CheckStatus(ByVal OrderId As String) As OrderInfo
End Interface
Interface IQuoteMgmt
    Function GetPriceQuote(ByVal newOrder As Order) As QuoteInfo()
End Interface
Public Class SupplierProxy
    Implements IOrderMgmt
    Implements IQuoteMgmt
    Private _ordermgmt As COrderMgmt
    Private _quotemgmt As CQuoteMgmt

    Public Function CheckStatus( _ 
                    ByVal OrderId As String) As OrderInfo _
            Implements InterfaceClient.IOrderMgmt.CheckStatus
        Return _ordermgmt.CheckStatus(OrderId)
    End Function

    Public Function PlaceOrder(ByVal newOrder As Order) _
           As String _
            Implements InterfaceClient.IOrderMgmt.PlaceOrder
        Return _ordermgmt.PlaceOrder(newOrder)
    End Function

    Public Function GetPriceQuote( _ 
                    ByVal newOrder As Order) As QuoteInfo() _
            Implements InterfaceClient.IQuoteMgmt.GetPriceQuote
        Return _quotemgmt.GetPriceQuote(newOrder)
    End Function

    Public Sub New(ByVal Url As String)
        _ordermgmt = New COrderMgmt()
        _quotemgmt = New CQuoteMgmt()
        _ordermgmt.Url = Url
        _quotemgmt.Url = Url
    End Sub
End Class

Each interface includes methods of the corresponding binding as defined in the WSDL document. A class, called SupplierProxy, implements both interfaces and contains instances of COrderMgmt and CQuoteMgmt. You can build the code in Listing 8.14 in a separate .dll and distribute it to client developers as a prepackaged interface-based proxy for your Web service. This is valuable if you are responsible for maintaining the Web service and the proxy classes and you want to abstract client developers from the details of your Web service's interface.

Listing 8.15 shows example client code that is designed to work against the interfaces IOrderMgmt and IQuoteMgmt.

Listing 8.15 An example client that works against the interfaces not the Web service proxy (VBWSClientCode\Chapter8\Interfaces\InterfaceClientForm1.vb)

Private Const SERVICE_URL As String = _ 
    "http://VBWSServer/vbwsbook/Chapter8/Supplier3.asmx"
Private Sub btnPlaceOrder_Click(ByVal sender As System.Object, _ 
           ByVal e As System.EventArgs) Handles btnPlaceOrder.Click
    Dim ws As IOrderMgmt
    ws = New SupplierProxy(SERVICE_URL)
    ws.PlaceOrder(MakeOrder())
End Sub
Private Sub btnQuote_Click(ByVal sender As System.Object, _ 
          ByVal e As System.EventArgs) Handles btnQuote.Click
    Dim ws As IQuoteMgmt
    ws = New SupplierProxy(SERVICE_URL)
    ws.GetPriceQuote(MakeOrder())
End Sub

To invoke the methods of the IOrderMgmt binding, the client declares a variable of type IOrderMgmt, then sets it to a new instance of SupplierProxy and proceeds to call PlaceOrder or CheckStatus. Similarly, to call methods of IQuoteMgmt, the client declares a variable of type IQuoteMgmt and sets it to a new instance of SupplierProxy and calls GetPriceQuote.

The code in Listing 8.15 makes it very clear that the client is programmed against an interface and not a specific implementation. However, there's still one glaring problem with this code: The Web service URL, which is the location of a specific implementation of IOrderMgmt and IQuoteMgmt, is hard-coded as a constant. The next sections deal with determining the Web service URL at run-time based on external configuration settings.

  • + Share This
  • 🔖 Save To Your Account