Web Service Interface Pattern


Intent

Provide interface-based client programming to the Web services world. Abstract a Web service class implementation using an interface (interface-based interaction).

Why is this common pattern considered advanced and a part of this chapter?

The structure behind the Web Service Interface (WSI) pattern is simple to implement and could have been discussed in the implementation patterns section earlier in the book. However, this was moved to this chapter for two reasons. First, because most Web service clients will use the facilities provided by Visual Studio .NET, I felt that any implementation that required manual editing of the generated Web service proxy code could be considered an advanced option. This will be explained shortly. Second, this pattern lends itself to a very rudimentary design pattern of interfaced -based programming and thus can also be considered either an architectural pattern or a technology-specific design (implementation) pattern. This is where pattern classification becomes difficult and why I try as much as possible not to classify my patterns. Patterns should not be pigeonholed.

Problem

Implementing a Web service in the .NET is rather simple, even when delving into more advanced functionality. By simply adding the Web service attribute to a System.Web.Services.WebService derived class, along with a Web method attribute marked operation, you can be off and running. Even more advanced Web service functionality, such as tracing input or receiving requestor information, has been made painless by the .NET CLR. However, the out-of-the-box implementation of the Web service framework forces the client to declare a reference of the Web service class when interacting with a Web service class or its generated proxy. For every Web service class implementation, each client must then declare and compile a class-based reference and be coupled to its specific method implementations . Currently, the .NET framework does not a provide means of abstracting a defined Web service, at least not by default.

It would be helpful if there were a way of abstracting Web service implementations so that the Web service client could interact with this abstraction. Those already familiar with interface-based programming have come to appreciate the ability to decouple their clients from method to method implementation details of any server with which they may be interacting. For something as commonplace as interface-based programming, you would think that this would be straightforward in .NET when implementing a Web service. For example, it is more straightforward to trace SOAP messages than it is to abstract a Web service (at least from the Web service client perspective). I guess no framework is perfect, and .NET has come close to providing almost everything else our hearts desire , so cutting Microsoft some slack would not be a bad idea. Fortunately, there is a way to provide an abstract-interface-based programming model to the world of .NET Web services.

Forces

Use the WSI Pattern when:

  • Multiple implementations of discrete Web service classes can be abstracted.

  • Polymorphism at the Web service level is needed to enhance and standardize functionality.

  • Web service classes contain methods with similar signatures but different implementations.

  • Implementing Web services in different development teams to standardize Web service development effort.

Structure

The structure of this pattern (Figure 7.3) is very similar to any other Web service class structure, other than the fact that there is an additional Web service class acting as the interface. This additional Web service class is actually an abstract class, and it will never be called. This additional entity represents only the description from which you can then obtain an interface definition. As you will see, it does not matter where you place the client-side interface that represents the abstracted Web service. The interface can go in some shared assembly or can remain local; the choice is yours. There is no trickery to making this work. The point of creating the additional Web service interface abstract class on the server is so that when the WSDL file is accessed and the client proxy code is generated, you now have a " server-controlled " version of this interface contract to work with. However, this entity is optional. As long as the interface is documented, the client can use any implemented interface code, provided that it matches the documented signature. Invoking any Web service class that implements the Web service interface is the same except that the client now casts the return value to the Web service interface. From there, the client can employ any Web service using polymorphism through this interface.

Figure 7.3. Web Service Interface generic class diagram.

graphics/07fig03.gif

The following class model (Figure 7.3) will be explained more in the implementation section, which should clear up any confusion.

Consequences

The WSI pattern has the following benefits and liabilities:

  • Abstracts the implementation of Web services from their representation . Using this pattern, Web service implementations can become abstract to Web service clients. This allows Web services to become standardized using the interface defined. Web service clients need only to instantiate the appropriate Web service class and from that point, they can interact with the Web service using the standard interface. Multiple teams can work on different implementations of the interface, abstracting clients from their implementations.

  • Isolates Web service clients from implementation changes . Using a standard interface to interact with the Web service will protect the client from implementation details. It helps protect the Web service client from server-side implementation changes.

  • Adds polymorphism to the Web services architecture . Polymorphism allows Web service clients to interact with multiple implementations of a Web service in a common fashion. This provides "true" interface polymorphism, using something not typically thought of as polymorphic ”Web services.

  • Adds the burden of having to modify the generated proxy code manually for each concrete Web service . The most annoying implementation of this pattern is the fact that you must manually edit the generated Web service proxy code. If you are automatically generating this from VStudio .NET, this may become somewhat repetitive.

Participants

  • ServiceClient () ” This represents the Web service client. The service client instantiates the Web service class like any other class but uses the declared Web service interface to interact with it. The Web service interface is declared like any other .NET interface. The interface is made accessible by either including an assembly with it declared as it is declared on the server or by using the WSDL -generated proxy as a guide for creating your own. As long as the interface signature matches the interface as used on the server ( IWebServiceInterface ), your code will compile.

  • ServiceProxy () ” This is the generated proxy code for all referenced Web services. This includes the Web service concrete implementations as well as the Web service interface ( WSI class) itself. The WebServiceInterface class is used to generate a proxy that can be used as a guide to create the client-side interface. You can also simply reference the service-side assembly containing the interface or create it manually using the generated Web service interface code as a guide.

  • IWebServiceInterface() ” This is the actual .NET interface used on the server to implement the interface-based functionality. This is also the external name given to the WebServiceInterface abstract class below and is the interface used by the client for interacting with all Web services that implement it. On the client, this can be generated by referencing the WebServiceInterface class's WSDL and creating it manually. Another option is to reference an assembly containing this interface. Using the WSDL method to create it manually on the client keeps you from having to provide the assembly to any Web service clients.

  • WebServiceInterface () ” This is actually an abstract Web service class that is externally represented using the IWebServiceInterface name ( [WebService(Name = "IWebServiceInterface",.. )]). This class will never directly be instantiated or called. It represents only a means of creating the interface contract on the client so that an interface can be used for interacting with all Web services that implement it on the server.

  • WebServiceConcrete() ” This is any normal Web service class implementation. It implements IWebServiceInterface on the server. Each WebServiceConcrete implementation is first directly instantiated by the client, then called using IWebServiceInterface 's methods.

Implementation

Listing 7.8 and Figure 7.4 show just one of the many implementation examples that can benefit from the WSI pattern. Sticking with our credit card system, an interface called IService has been created that contains a method called Execute . This method is passed a DataSet containing the necessary credit card information to authorize a transaction. The Execute method acts as a factory method for the remainder of the financial component required to perform the unit of work. This interface is the starting point of this pattern. This becomes the "contract" upon which the abstract Web service interface, called FinancialServiceFactory , implements and mimics by externally exposing itself as IService. Using the WSI pattern, we can now abstract all services using the IService as the interface contract with which all Web service clients will interact.

Figure 7.4. WSI implementation class diagram.

graphics/07fig04.gif

The code in Listing 7.7 shows our simple interface, which happens to be defined in FinancialServiceFactory.asmx.cs.

Listing 7.7 Sample interface.
 interface IService {    // any signature can be used    DataSet Execute(DataSet ds); } 

Figure 7.4 shows one concrete implementation of the IService interface called CreditCardService . The CreditCardService acts like any other Web service class but must implement IService, as shown in Listing 7.8.

Listing 7.8 One concrete WSI implementation example.
 [WebService(Namespace="http://www.etier.com/patterns.net",    Description = "This provides the first implementation of the Web Service Interface, Any Concrete Implementation will do.")] public class CreditCardService : System.Web.Services.WebService,    IService {    public CreditCardService()    {       InitializeComponent();    }    . . .    [WebMethod(Description = "Implements Execute")]    public int Execute()    {       .  .  .    } . . . } 

FinancialServerFactory is the abstract class that is externally represented as the IService interface, as explained in the previous sections. Using the Name property of the WebService attribute, we define IService as what will be represented in the generated WSDL when referencing the FinancialServiceFactory Web service from the client. The FinancialServiceFactory code is shown in Listing 7.9.

Listing 7.9 Web service "piece" of the WSI implementation.
 [WebService(Name = "IService", Namespace="http://www.etier.com/patterns.net",    Description = "This web service is abstract and cannot be    directly called.")] abstract class WebServiceInterface : ICanBeAnyInterface {    [WebMethod(Description = "Defines as a WebService Interface       Execute from IService")]    abstract public int Execute(); } 

Once these service elements are defined, the client can now interact with the IService interface directly, with one minimal change. The final adjustment that must be made on the client is to modify the generated proxy for each concrete Web service (CreditCardService, in our case). Simply set IService as the implemented interface in the actual proxy code once it is generated from WSDL. Listing 7.10 shows where you must add the IService interface before you can begin interacting with any concrete implementations.

Listing 7.10 WSDL-generated proxy code ”highlighting where to add interface declaration.
 [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Web.Services.WebServiceBindingAttribute(Name=    "CreditCardServiceSoap",    namespace="http://www.etier.com/patterns.net")] public class CreditCardServiceSoap :    System.Web.Services.Protocols.SoapHttpClientProtocol,  IService  {    /// <remarks/>    public CreditCardService() {       . . .    }    /// <remarks/>    . . . } 

The interface IService must be defined somewhere on the client. You can define this manually, reference it directly, or infer it from the WSDL generated from the abstract Web service we created earlier (FinancialServiceFactory). Once you've defined the IService interface on the client, you may interact with any Web service using the IService interface. A simple interaction is shown in Listing 7.11.

Listing 7.11 Client-side implementation sample of WSI.
 IService oWSI; DataSet oDsIn = null; DataSet oDsOut = null; // instantiate each web service using the interface we are now externalizing oWSI = (IService) new localhost.CreditCardService(); . . . // any interface method calls are polymorphic oDsOut = oWSI.Execute(oDsIn); . . . 

As you can the see, the Web service can now be treated like any other implementation class that implements any interface. Although there are a few hoops to leap through initially, the benefits significantly outweigh the hassles of providing you this useful pattern.



.NET Patterns. Architecture, Design, and Process
.NET Patterns: Architecture, Design, and Process
ISBN: 0321130022
EAN: 2147483647
Year: 2003
Pages: 70

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