Using Remoting
There are three separate programs that must be created to build
an application that uses remoting:
·
A remote class that allows clients to access and
use the methods contained in the class.
·
A server program that advertises and hosts the
server class on a machine
·
A client program that uses the server class
methods
This section describes how to configure each of these parts so
you can create C# network programs that utilize remoting.
Creating the Remote Class Proxy
Each remoting application requires a set of methods that
can be accessed by clients on a network. Like serialization classes, these
methods must be contained in a special class and compiled into a proxy library
object that is used in the server and client programs.
To identify a class as a remote class, it must be derived from
the MarshalByRefObject class. This allows clients to
access the remote class methods by reference through a proxy. Listing 16.8 is
the MathClass.cs program, which defines a class to use
as a remote class in the example programs.
Listing
16.8: The MathClass.cs
program
using System;
public class MathClass MarshalByRefObject
{
public int Add(int a, int b)
{
int c = a + b;
return c;
}
public int Subtract(int a, int b)
{
int c = a - b;
return c;
}
public int Multiply(int a, int b)
{
int c = a * b;
return c;
}
public int Divide(int a, int b)
{
int c;
if (b != 0)
c = a / b;
else
c = 0;
return c;
}
}
The MathClass class is derived from the MarshalByRegObject class, which means it can be a remote
class in a server program. It defines four common math functions that can be
called by remote network clients. Each function receives two parameters from
the client and returns the corresponding value, which will be sent back to the
client.
Similar to the serialization technique, you must make a library
DLL file from the remote class program. This is done using the /t:library option of the csc
compiler:
csc /t:library MathClass.cs
The MathClass.dll file contains all the
information necessary for the server and client applications to access the data
elements and methods in the remote class.
|
Warning
|
Also similar to the serialization technique, you must
ensure that the same proxy class library file defines the remote class for
both the server and client programs. If a different proxy class library is
used for each program, the serialization will not work, and the remoting
function will fail. Also remember that the proxy class library is referenced
by class name, not filename. Make sure that the class library references the
proper class name.
|
Creating the Server Program
The server program hosts the remote class on the network,
accepting requests from clients and passing them to the remote class. The
server program must register a channel to support the communication with the
remote class and then register the remote class as a service in the .NET
remoting server.
There are three steps to building the server program for the
remote class:
1.
Create a communication channel to support access
to the remote class.
2.
Register the communication channel with the
remoting channel services.
3.
Register the remote class as a service with the
remoting services.
Create a Communication Channel
First, a communication channel must be defined. .NET
remoting has two separate classes for the two types of communication channels
used for network access: TcpChannel and HttpChannel.
TcpChannel The TcpChannel
class, defined in the System.Runtime.Remoting_.Channels.Tcp
namespace, receives and sends data in a binary format within TCP packets for
the remote class. The TcpChannel class instance is
created using the TCP port that will listen for incoming requests for the
remote class:
TcpChannel chan = new TcpChannel(9050);
By default, the TcpChannel
class uses the BinaryFormatter class to serialize all
data sent and received on the channel.
HttpChannel The HttpChannel
class, defined in the System.Runtime.Remoting_.Channels.Http
namespace, sends data using the SOAP format within an HTTP session for the
remote class. The HttpChannel instance also uses a TCP
port number to accept HTTP requests on for the remote class:
HttpChannel chan = new HttpChannel(9050);
By default, the Httpchannel
class uses the SoapFormatter class to serialize all
data received and sent on the channel.
Register the Communication Channel
After you create either the TcpChannel
or HttpChannel object, it must be registered with the
system before it can receive network messages. The RegisterChannel()
method of the ChannelServices class registers new
channels on the system. The ChannelServices class is
found in the System.Runtime.Remoting.Channels
namespace:
ChannelServices.RegisterChannel(chan);
The sole parameter (chan)
identifies the channel to register, which can be either a TcpChannel
or a HttpChannel object:
Register the Remote Class Service
After the communication channel is created and registered,
the server program must register the remote class as a service on the system.
The System.Runtime.Remoting namespace contains the RemotingConfiguration class, which configures a new service
for the remoting system. This class specifies the configuration parameters used
when registering the service with the remoting service. The parameters that
must be specified are shown in Table 16.1.
Table 16.1: The RemotingConfiguration Parameters
|
Parameter
|
Description
|
type
|
The full type name of the remote class object, along with
the assembly filename where the class is defined
|
objectUri
|
The URI of the remote class object
|
mode
|
How the server will handle calls to the remote class
object
|
The type parameter specifies both the
class name and the DLL filename where the remote class definition can be found.
Because the MathClass example used the same name for
the DLL filename as the class name, it would be defined as the following:
type="MathClass, MathClass"
The objectUri parameter defines a unique
URI value to represent the remote class on the server. This value does not have
to be related to the remote class name in any way, but to avoid confusion on
servers with multiple remote classes, it often helps to make it somewhat
related to the class name used.
You must also specify whether to use the SingleCall
or Singleton object mode to handle incoming requests
for the remote class. This is done with the mode option:
mode = "SingleCall"
After determining the RemotingConfiguration
parameters necessary for defining the remote class on the remoting server, you
must declare them in the server program. There are two ways to do this, either
using a separate configuration file (using XML format), or through statements
within the server program.
Using a Separate Configuration File
When you use a configuration file, it contains XML tags to
identify the required parameters for the RemotingConfigutation
object. Listing 16.9 shows a sample configuration file for defining the MathClass remote class on the server.
Listing
16.9: The server.xml
configuration file]
<configuration>
<system.runtime.remoting>
<application>
<service>
<wellknown
type="MathClass, MathClass"
objectUri="MyMathServer"
mode="SingleCall"
/>
</service>
</application>
</system.runtime.remoting>
</configuration>
After the configuration file is created, you must use the Configure() method to read the parameters from the file. The
following example assumes that the server.xml file is
located in the same directory as the server program:
RemotingConfiguration.Configure("server.xml");
If that is not the case, a full path name must reference the
configuration file.
Using Program Statements
Instead of using a separate configuration file, the RegisterWellKnownServiceType() method can define the
properties of the remote class within the application program:
RemotingConfiguration.RegisterWellknownServiceType(
Type.GetType("MathClass, MathClass"), "MyMathServer",
WellKnownObjectMode.SingleCall);
The same parameters in the configuration file are defined within
the RegisterWellknownServiceType() method.
The drawback to defining the parameters in the program
statements is that they are not easily changeable in dynamic environments. If
your application is in an environment that will not change, defining the
parameters using the RegisterWellknownServiceType()
method may perform better.
The Full Server Program
Putting all of the pieces together, the MathServer.cs
program (Listing 16.10) demonstrates how to create a remoting server program
that hosts the remote class object.
Listing
16.10: The
MathServer.cs program
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
public class MathServer
{
public static int ""on"">Main()
{
HttpChannel chan = new HttpChannel(9050);
ChannelServices.RegisterChannel(chan);
RemotingConfiguration.RegisterWellKnownServiceType(
Type.GetType("MathClass, MathClass"), "MyMathServer",
WellKnownObjectMode.SingleCall);
Console.WriteLine("Hit <enter> to exit...");
Console.ReadLine();
return 0;
}
}
The MathServer program creates and
registers an HttpChannel using port 9050 to receive
requests for the MathClass remote class object. Once
the information is registered, the server program must stay active for the
service to accept incoming requests. Once the program exits, the service will
be removed from the remoting system. To ensure the server program remains
active, a simple Console.ReadLine() method waits for
an Enter key from the keyboard.
The server program must be compiled with the MathClass.dll
file so it knows about the MathClass remote class
definitions:
csc /r:MathClass.dll MathServer.cs
Creating the Client Program
The client program connects to the server program and
utilizes the methods hosted in the remote class object. Similar to the server
program, the client program must create a communication channel (the same type
the server uses), and must register the channel with the local remoting system
on the client machine:
HttpChannel chan = new HttpChannel();
ChannelServices.RegisterChannel(chan);
Because the client program does not need to listen to a specific
port, it does not need to specify a port number in the HttpChannel
constructor.
After the channel is created and registered, you can instantiate
the proxy class to create an object of the remote class. This proxy class
mimics the functionality of the remote class for local calls. When the proxy
receives a call to a method for the remote class, it passes the call via the
established communication channel to the server. The server receives the call
and passes it to the remote class, which processes the call and passes any
return information through the server program back to the proxy class.
There are two ways of creating the proxy object in the client
program:
·
Registering the remote class as a client type in
the remoting system and creating a new instance of the remote class for the
proxy class
·
Using the Activator
class to register the remote class information for the proxy class
Registering the Remote Class Proxy Object
Similar to the server program registering the remote class,
the client program can also use the RemotingConfiguration
class to register the information needed to make a proxy object that contacts
the remote class server. The Activator class in the System namespace is used for this. This class creates proxy
objects that pass method calls from an application to the appropriate location,
either within the local program, or in the case of remoting, to the appropriate
remote URI location of the remote class. The GetObject()
method defines the location of the remote class for the proxy object.
The GetObject() method requires two
parameters, the type of the remote class and the URI to which to pass requests:
Activator.GetObject(Type objecttype, string uri)
The objecttype parameter
defines the remote class name that is used, while the uri
parameter defines where to access the remote class.
The Full Client Program
The MathClient.cs program in
Listing 16.11 demonstrates how to create a client program that can access the
remote class methods hosted by the server.
Listing
16.11: The
MathClient.cs program
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
public class MathClient
{
public static int ""on"">Main (string[] argv)
{
HttpChannel chan = new HttpChannel();
ChannelServices.RegisterChannel(chan);
MathClass obj = (MathClass)Activator.GetObject(
typeof(MathClass), "http://127.0.0.1:9050/MyMathServer");
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;
}
}
After the proxy object is created, the MathClient
program proceeds to use the various class methods defined in the MathClass class to process data. Each time a class method is
called, the proxy class forwards the data across the network to the server
program, which processes the data and returns the result to the proxy class.
You can test the programs out and see that the MathClient
functions work as advertised:
C:\>MathClient 1 5
a + b = 6
a - b = -4
a * b = 5
a / b = 0
C:\>MathClient 100 50
a + b = 150
a - b = 50
a * b = 5000
a / b = 2
C:\>
If you are using separate devices to run the MathServer and MathClient programs
(assuming you changed the URL in the client program), you can use the WinDump
or Analyzer programs to watch the transactions as they cross the network.
Because an HttpChannel channel was used for
communication, all of the transactions will be in XML format, which makes it
easier to read.