Nov. 1, 2008, 2:36 p.m.
posted by vendetta
Creating a Proxy Class Using soapsuds
The remoting example shown in this chapter assumed one important fact - that you were in control of both the remoting server and the client application. In the real world, this may not be (and often is not) the case. You may run into a situation where you are asked to write a client application that uses the methods hosted by a remoting server without much (if any) knowledge of how the remote class is defined. This section describes how you can build a remoting client application even if you don’t have the original remote class file used to create the client.
Viewing the Remote Class Interfaces
When the HttpChannel is used for communication with the remoting server, the remote class definition can be viewed using a normal web browser. The URI registered for the remoting server represents how the remote class is accessed via the web. To see the class interfaces, you must add the tag ?wsdl to the end of the URI:
http://192.168.1.100:9050/MyMathServer?wsdl
This URI produces the standard SOAP web page that defines the MathClass class in Listing 16.8. Each of the individual methods in the class is defined within the Web Services Definition Language (WSDL) page, along with definitions for each of the parameters and return values. Figure illustrates part of the WSDL definition.
Instead of manually creating the library DLL file for the remoting proxy class, you can do it with the WSDL definition and the soapsuds program.
The soapsuds Program
The .NET Framework SDK package contains the soapsuds program, which extracts class information from remote classes (you may remember this function from the wsdl program, which was discussed in the "Web Services" section in Chapter 14). The extracted information forms the DLL proxy file necessary to communicate with the remote class from a client application.
The soapsuds program offers a healthy collection of command-line options that produce many features, as described in Figure.
|
Option |
Specifies |
|---|---|
|
-d:domain |
The domain name to use when connecting to a server |
|
-gc |
To generate C# code for the connected server |
|
-hpn:name |
An HTTP proxy server to use to connect to the server |
|
-hpp:port |
An HTTP proxy port to use to connect to the server |
|
-ia:file |
An input assembly file |
|
-id:dir |
Location of the input DLL files |
|
-is:file |
The input XML schema file |
|
-nowp |
Not to create a wrapped proxy |
|
-oa:file |
The file to save the output information |
|
-od:dir |
The directory of the output file |
|
os:file |
The file to save the XML schema information |
|
p:password |
A password to use to connect to the server |
|
pn:namespace |
The proxy namespace for the code in the generated proxy file |
|
sdl |
To generate Service Description Language (SDL) formatted files |
|
se:url |
The URL for the service endpoint to place in the output file |
|
sn:file |
The file that contains the key pair used to sign the assembly |
|
types:info |
The input type list |
|
url:url |
The URL of the service from which to retrieve the XML schema |
|
u:username |
The user name that connects to the server |
|
wp |
To create a wrapped proxy |
|
wsdl |
To generate Web Services Description Language (WSDL) formatted files |
Of all these command-line options, the most common are the -url option (to specify the remote class URI), and the -oa option (to specify the DLL file to store the information.
Building the Proxy Class
The following command creates a basic DLL proxy file to replace the original remote class file:
soapsuds -url:http://192.168.1.100:9050/MyMathServer?wsdl -oa:MathClass.dll -nowp
The resulting MathClass.dll file then creates the client application; this is just like the original class file that was manually created (see Listing 16.8). You can also add the -gc command-line option to generate the C# code that created the DLL file (see Listing 16.13).
using System;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Metadata;
using System.Runtime.Remoting.Metadata.W3cXsd2001;
[Serializable, SoapType(XmlNamespace=@"http://schemas.microsoft.com/clr/assem/_Â MathClass%2C%20Version%3D0.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3_Â Dnull", %3D0.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull")]
public class MathClass : System.MarshalByRefObject
{
[SoapMethod(SoapAction=@"http://schemas.microsoft.com/clr/nsassem/_ Â MathClass/MathClass#Add")]
public Int32 Add(Int32 a, Int32 b)
{
return((Int32) (Object) null);
}
[SoapMethod(SoapAction=@"http://schemas.microsoft.com/clr/nsassem/_ Â MathClass/MathClass#Subtract")]
public Int32 Subtract(Int32 a, Int32 b)
{
return((Int32) (Object) null);
}
[SoapMethod(SoapAction=@"http://schemas.microsoft.com/clr/nsassem/_ Â MathClass/MathClass#Multiply")]
public Int32 Multiply(Int32 a, Int32 b)
{
return((Int32) (Object) null);
}
[SoapMethod(SoapAction=@"http://schemas.microsoft.com/clr/nsassem/_ Â MathClass/MathClass#Divide")]
public Int32 Divide(Int32 a, Int32 b)
{
return((Int32) (Object) null);
}
}
The proxy class file generated by soapsuds reproduces the code for the remote class, showing how each class method is defined and what parameters are within the class. After soapsuds creates the DLL file, you can write the client program, just you did when the DLL file was manually created:
csc /r:MathClass.dll MathClient.cs
The MathClient.exe file generated by this compile behaves exactly as the executable generated from the original proxy class file in Listing 16.11.
Using Wrapped Proxies
In the previous soapsuds example, which generated Listing 16.13, the -nowp option produced the generic code to access the remote class. This allows the client to access the remote class from whatever remoting server the class is hosted on. The RemotingConfiguration information is compiled into the client application to determine from where the remote class will be accessed.
Alternatively, if you do not include the -nowp option on the soapsuds command line, soapsuds creates a wrapped proxy, which handles all of the remoting communication configuration features. This includes building a constructor of the remote class, indicating how to connect to the URI specified in the soapsuds command. If you use the -gc command-line option, you can see the class constructor section:
// Constructor
public MathClass()
{
base.ConfigureProxy(this.GetType(), @"http://192.168.1.100:9050/ Â
MyMathServer");
}
When using the wrapped proxy option, the class constructor created specifies exactly where the remote class can be accessed, so no RemotingConfiguration section is needed in the client application. All the client needs to create is an instance of the remote class; the remoting system automatically knows how to access the class methods. Listing 16.14 shows the NewMathClient.cs program, which uses this technique to access the remote class.
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
public class NewMathClient
{
public static int Main(string[] argv)
{
HttpChannel chan = new HttpChannel();
ChannelServices.RegisterChannel(chan);
MathClass obj = new MathClass();
if (obj == null)
System.Console.WriteLine("Could not locate server");
else
{
int a = Convert.ToInt32(argv[0]);
int b = Convert.ToInt32(argv[1]);
int c = obj.Add(a, b);
Console.WriteLine("a + b = {0}", c);
c = obj.Subtract(a, b);
Console.WriteLine("a - b = {0}", c);
c = obj.Multiply(a, b);
Console.WriteLine("a * b = {0}", c);
c = obj.Divide(a, b);
Console.WriteLine("a / b = {0}", c);
}
return 0;
}
}
Notice that using the wrapped proxy DLL makes the actual client code cleaner. All you need to do is create a new MathClass object using the default constructor, and the proxy wrapper does the rest. However, as discussed, the network address information of the remote class server is hard-coded into the proxy class. If the remote class server changes, the proxy class must be re-created.
