Combine Polymorphism and Web Services

Introduction

Happy New Year!

You may be aware of polymorphism, and you probably know something about Web services by now too. But, what about polymorphism across Web services? This article reviews polymorphism, demonstrates XML Web services, and most importantly, shows you how to combine polymorphism and Web services.

Polymorphism

Those very experienced with object-oriented programming (OOP) are comfortable with polymorphism, but not everyone is experienced with OOP. If you are in the former group, skip ahead to the section “XML Web Services.” If you are in the latter group, keep reading.

Before object-oriented languages, if one wanted to print different data types, one would write methods such as PrintInteger(int i), PrintString(string s), and PrintFloat(float f). That is, one had to differentiate the behavior and data type by name because a pre-OO language such as C wouldn’t permit one to write methods with the same name, even if their argument types were different.

The advent of C++ permitted method overloading—among other things. Thus, one could write Print(int i), Print(string s), and Print(float f), and based on the data type, the code would call the correct Print method. Method overloading is simply supported by a name-mangling scheme where the compiler creates unique names internally by replacing the names with bits and pieces from the name and argument list. So, while you code Print(1), the compiler may internally rename the Print method with a prefix derived from the parameter type so that Print(1) becomes i_Print(1).

Method overloading is a form of polymorphism. Name mangling is a mechanism that supports method overloading. More commonly, polymorphism is associated with inheritance. Inheritance is where a new class (called the subclass) gets part of its definition from the inherited class (called the superclass) and adds new information. If you overload methods in the same class, the data types must be different. If you overload methods in an inheritance relationship, methods in the subclass and superclass may have the same signature, and the mangler produces the same mangled name.

For instance, suppose a superclass defines a Print(int i) method and a subclass it inherits from also defines a Print(int i) method. Use polymorphism to call Child.Print(int) when you have an instance of Child but Parent.Print(int) when you have an instance of Parent. This is inheritance polymorphism: the same name and signature but different classes.

Inheritance polymorphism uses an additional mechanism in conjunction with name mangling. The compiler adds methods to an array of methods called a virtual methods table (VMT). Each class has an index into the VMT, so when Print(int) is called, the compiler is routed to the VMT for the Print methods and the class’s internal index (its Delta or ?) is used to index to a slot offset from the beginning of the VMT plus the Delta. This way, the correct implementation of the method is called. The compiler manages all VMT indexing and class Deltas.

In a nutshell, polymorphism enables you to define many method forms with very similar names, which yields nice name semantics. OOP compilers, in turn, will figure out which method you mean based on the class of the caller. One of polymorphism’s best benefits is that you no longer have to write this kind of code (using pseudo code here):

If type of arg is integer then
  PrintInteger(arg)
Else if type of arg is string then
  PrintString(arg)
Else if type of args is float then
  PrintFloat(arg)

You simply write:

Print(arg)

The compiler and its polymorphic mechanisms figure out the correct version of the print method to call by generating a methods-indexing scheme that is for practical purposes equivalent to the conditional code above.

For an authoritative description of the inner workings of OOP idioms from the language’s perspective, pick up Bjarne Stroustrup’s The C++ Programming Language (ISBN: 0201700735) from Addison Wesley. Many OOP languages use mechanisms very similar to the C++ implementation.

XML Web Services

If you are pretty comfortable with the mechanics of XML Web services and the motivation for using them, skip to the next section: “Supporting Polymorphism with Web Services.”

In the past ten years or so, distributed applications have become more prevalent. As is common with many kinds of engineering, software goes through a period of invention and then standardization. XML Web services are a standardization based on the open protocols of HTTP and XML. XML Web services do not belong solely to Microsoft, but Microsoft does offer an implementation of XML Web services based on the .NET Framework and its attributes.

The basic idea is that you write code to add the WebServiceAttribute to classes representing the Web service and the WebMethodAttribute to the methods in those classes representing Web methods—or methods you want to permit consumers to call. Microsoft technology uses reflection and code generation to generate proxy types and code that make calling these distributed services and methods easy. In addition to generating proxy code, the .NET Framework and Visual Studio include a wizard that stubs out a Web service and Web method for you.

To create a Web service, run Visual Studio and select File|New|Project. Pick the ASP.NET Web service applet from the Templates list in the New Project dialog (see Figure 1).

Figure 1: Create your first Web service with point-and-click ease.

To run the sample Web service and Web method, uncomment the HelloWorld sample method that the project template wizard created and run the solution. For more information on producing, consuming, and using XML Web service tools in general, see previous VB Today columns, particularly “Building Distributed Apps? Use XML Web Services, Not Remoting (Mostly)” from December 2004.

Supporting Polymorphism for XML-Generated Proxy Classes

Now, turn your focus to the purpose of this article.

When you define parameters and return arguments for Web methods, a utility called Web Services Discovery Language (or whizdahl) invokes another tool called SPROXY. SPROXY uses reflection and the CodeDOM to figure out a definition for the types declared in your Web methods and then generates proxy classes for compound types. For example, if you have a class named Person, SPROXY will generate a Person class when a consumer uses the Web service. The benefit is that Web service producers don’t have to ship their proprietary code to consumers for consumers to use their code. SPROXY does the work for them. Using proxy code permits businesses to protect proprietary business rules while still selling access to the overlying features of those rules.

Here are examples of a Person class (see Listing 1) and a generated Person proxy (see Listing 2).

Listing 1. The Person Class Behind the Web Service

public class Person
{
private string name;
  public Person(){}

  public Person(string name)
  {
    this.name = name;
  }

  public string Name
  {
    get{ return name; }
    set{ name = value; }
  }

  public string GetUpperName()
  {
    return name.ToUpper();
  }

  public string UpperName
  {
    get{ return GetUpperName(); }
    set{}
  }
}

Listing 2. The Proxy Version of the Person Class as Generated by SPROXY

public class Person
{
/// <remarks/>
        public string Name;
}

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read