Developing SOAP Applications

The Microsoft .NET Framework provides comprehensive support for developing both SOAP clients/consumers and servers/producers using a variety of different technologies and methods. In this section we take a closer look at some ways you can develop SOAP applications.

Using Web Services

ASP.NET offers excellent support for creating XML Web services based on SOAP servers. Support for XML Web services provided through ASP.NET is contained within .asmx files, which are text file, similar to .aspx files. Over the next few pages we will look at some simple examples that build both clients and servers. These, of course, will interact as XML Web services.

The Server

Listing 14-10, hello.asmx, shows a simple Web Service .asmx file. This program returns nothing more than a string to the requesting client.

Listing 14-10 hello.asmx: A simple Web Service.

<%@ WebService Language="C#" Class="Hello" %>
using System;
using System.Web.Services;
public class Hello : WebService
{
  [WebMethod] public String SayHello( String Name )
  {
    return ( "Hello " + Name );
  }	
}
This particular Web Service is implemented in C#, but you could also use any other language built on the .NET Framework, such as Visual Basic .NET.

The first line in hello.asmx declares that this is an XML Web service and sets the language (C# in this case) used to implement this service. Next we import the necessary System.Web.Services namespace and declare that our class is derived from the WebService base class. Finally, to indicate that our GetStockPrice method will be accessible as part of the service, we marked it with the [WebMethod] custom attribute.

To allow client applications to consume this Web Service you need to create a proxy class DLL. This DLL wraps all the code and calls in the associated Web Service into a simple method call similar to a COM object. With the .NET Framework SDK, you will use a tool called WebServiceUtil.exe to perform this task. Use the following:

WebServiceUtil /c:proxy /pa/Hello.asmx?SDL /n:nsHello

to generate a proxy class called Hello.cs. Next you need to compile this Hello.cs into a DLL with the following command:

csc /out:Hello.dll /t:library /r:system.data.dll /r:system.web.
services.dll /r:system.xml.serialization.dll Hello.cs

The Client

The Hello Web Service hello.asmx can be accessed by a client that knows how to consume SOAP messages. For example, we will develop a simple ASP.NET page that will consume this XML Web service. This is shown in Listing 14-11.

Listing 14-11 hello_client.aspx: An ASP.NET consumer of the Hello Web Service.

<%@ Import Namespace="nsHello" %>
<html>
  <script language="VB" runat="Server">
    Sub Greeting( Src as Object, E as EventArgs )
      Dim h as New Hello
      lblGreeting = h.SayHello( edtName.Value )
    End Sub
  </script>
  <body>
    <form runat="SERVER">
      Your name:
      <ASP:INPUT ID="edtName" TYPE="Text" RUNAT="Server"/><br/>
      <ASP:BUTTON TEXT="Say Hello!" onclick="Greeting"/>
    </form>
    <h1 ID="lblHello" RUNAT="Server"/>
  </body>
</html>

This ASP.NET first imports the Hello Web Service proxy class DLL using the namespace defined. The actual call to the Hello Web Service happens in the Greeting procedure in HelloClient.aspx. The New keyword is used to instantiate the object. Once instantiated, we simply invoke the SayHello method to do the job.

For those of you familiar with Microsoft programming methodology and technology, this approach is similar to how you would use a COM object. Behind the scene the Hello Web Service proxy class DLL packages our method call within a SOAP message and transfers it over the wire to our Hello Web Service for processing. The Hello Web Service then parses the SOAP message and invokes the SayHello method. The result is then packaged as a SOAP response message and once again passed by the proxy class DLL. And all this time you think you are making only a simple method call!

Using Components

Microsoft .NET Remoting enables developers to produce remote-managed, native COM/COM+, and serviced components (managed components serviced by COM+ services). What makes the .NET implementation important is that these components are built as SOAP endpoints from any process, including console applications, GUI applications, Windows NT Services, and IIS. Because they are built on this standard for communication, the number of applications that ultimately can interface with the components is increased, and chances for success in heterogeneous environments are improved.

In this section we will look at both server and client components. We are going to step through some simple examples to show you how they work and how easy it is to build them.

The Server

Listing 14-12, hello.cs, shows a simple .NET managed component that exposes the SayHello method that will be accessible through SOAP.

In hello.cs the Hello object is remotable by extending the MarshalByRefObject class. This allows the SayHello method to be accessed through SOAP when this object is exposed by a suitable host that acts as the SOAP endpoint. An example of such a host is shown in Listing 14-13, hello_host.cs, which builds a service waiting for a connection. The user is able to stop the service, as you will see near the end of the listing, by pressing the Enter key.

Listing 14-12 hello.cs: A managed component.

using System;
namespace nsHello
{
  /* Define the Service */
  public class Hello : MarshalByRefObject
  {
    /* This method will be called remotely by our client */
    public String SayHello( String Name )
    {
      return ( "Hello " + Name );
    }
  }
}

Listing 14-13 hello_host.cs: Creates a service listening for connections.

using System;
using System.IO;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels.HTTP;
public class HelloHost
{
  public static void Main( String[] args )
  {
    /* Manually load the http channel. 1099 is the port # */
    ChannelServices.RegisterChannel( new HTTPChannel( 1099 ) );
    /* Register the wellknown server type */
    RemotingServices.RegisterWellKnownType(
      "nsHello",                       // Assembly
      "nsHello.Hello",                 // Full type name
      "host/Hello.soap",               // URI
      WellKnownObjectMode.Singleton ); // Object Mode
    /* Wait until the user wants to exit */
    Console.WriteLine( "Listening for requests - Press ENTER to exit" );
    String keyState = Console.ReadLine();
  }
}

In the .NET Framework messages are transported to and from remote objects through Channels Objects that encapsulate the underlying network protocols used to make the client/server communication. In hello_host.cs we indicated that we would like to use the built-in HTTP Channel, which transports messages using the SOAP protocol.

Now that we have our code in these two files, we must compile them. As mentioned earlier, this task can be accomplished using the csc C# compiler. A simpler process, however, would be to use a makefile. These files contain a list of compilation commands used to compile one or more code files. For our example, use Listing 14-14, makefile, to build hello.cs and hello_host.cs.

Listing 14-14 makefile: A makefile for building hello_host.cs and hello.cs.

all: hello_host.exe hello.dll
hello_host.exe: hello_host.cs
	csc /r:System.Runtime.Remoting.dll hello_host.cs
hello.dll: hello.cs
	csc /t:library hello.cs

The Client

Now that the server is created we can focus on the client. Listing 14-15, hello_client.cs, is an application that will consume the service exposed by our hello_host.cs to invoke the SayHello remote method.

Listing 14-15 hello_client.cs: A consumer of the hello_host.cs.

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels.HTTP;
using nsHello;
public class HelloClient
{
  public static Main( String[] args )
  {
    /* Obtain a Proxy to the SOAP URL */
    Hello h = (Hello)Activator.GetObject( 
                 typeof(Hello),                             
                 /host/Hello.soap" );
    /* The following occurs over SOAP to HelloHost */
    Console.WriteLine( h.SayHello( "Dick" ) ); 
  }
}    

In hello_client.cs we used the GetObject method instead of the new keyword to activate the remote object because we are manually activating the object. Had we used the remote configuration file, we could have used the New keyword to the same effect.

As with the previous example, we need to compile the application. The following command will build the hello_client.cs:

	csc /r:System.Runtime.Remoting.dll /r: hello.dll hello_client.cs

Once both the server and client applications are built, we can test them by first running hello_host.exe in one window and then running hello_client.exe in another. You will see hello_client.exe respond with the message "Hello Dick" on your screen.