.NET Remoting
Last Updated: 2001
Channels:
Not all channels are bi-directional (although the defaults
implementations of TCP & HTTP are)
HTTP: Slow, but can use SSL.
TCP: Fast, but not secure. Requires a port number.
Two basic methods:
Copy (or MBV - Marshall By Value)
Object is serialised to the remote location and run there. Thus candidates for
MBV must not have references to objects on the client or hold PC specific
information (such as an open file handle).
An object is declared serialisable by either implementing ISerializable
(allowing the coder to control serialisation) or by decorating the class
using the [SerializeAttribute] attribute (leaving it to the framework controls
serialisation).
Reference (or MBR - Marshall By Reference)
Inherit from System.MarshalByRefObject.
Class Access:
Static Members
Never remoted. Accessed directly as a memory location.
Instance Fields & Accessors
System checks at run-time whether the object is a proxy or not. If its not
then access is direct, otherwise the proxy supplies the accessors.
Private Methods
Cannot be remoted.
Delegates
Delegates are always MBV objects. The object supplied to the delegate can be
of any (remotable) type.
MBR Activation:
Server Activation (where the server controls the lifespan of the object)
Uses new (and settings in a configuration file) or
Activator.GetObject(...)
Not created on the server until a method on the proxy is
called.
Calling "new" or Activator.GetObject(...) will not trigger the creation. This
saves a round trip to the server but does mean Server Activation is only
available to objects with only default constructors.
(Activator.GetObject(...) is used in place of new when requesting a particular
interface rather than a specific class)
Can be activated as a Singleton
All subsequent requests for that object (including from other clients) will be
severed by the same object (until its lifespan ends when a new Singleton will
be generate in response to the first call).
Can be activated as a SingleCall
The objects is only used for one call and a new object is created with the
next call (even if the old one hasn't been destroyed yet)
Client Activation (where the client controls the lifespan of the object)
Configuration:
The configuration file used with the new command can be loaded using RemotingConfiguration.Configure(...). Multiple configuration files can be use at once.
Alternatively, remoting can be configured programmatically using ChannelServices.RegisterChannel(...) and the RemotingConfiguration object (for examples, see source code later)
This requires three projects (which can all be placed in the same project):
The Remoted Class Project:
[This sample is based on a C# class library template to ensure we get a DLL. For the purposes of this example, either call the project RemoteTest, change the output name to RemoteTest or change all later references to RemoteTest to whatever you called this project]
using
System;
using System.Diagnostics;
namespace DavesRemoteObject {
// The class that will be remoted (by reference since we inherit from MarshalByRefObject)
public class DaveMath : MarshalByRefObject {
public int Add2ANumbers (ANumber number1, ANumber number2) {
return number1.Value + number2.Value;
}// A method to indicate where we are executing
public void WhereAmI() {
Console.WriteLine("WhereAmI was executed in: " + Process.GetCurrentProcess().ProcessName.ToString());
}
} // A class that we'll pass to and from the remoted object (by value as we've marked it Serializable]
[Serializable]
public class ANumber {
// Property to hold the number & its accessors
private int _Value;
public int Value {
get {return _Value;}
set {_Value = value;}
}
}
}
The Remote Server Project
[The name of the project here doesn't matter as we will be listening on a channel for a specific URI. This project should be based on the C# Console template so that we can easily output text.
The following references need to be added to the project:
System.Runtime.Remoting
The remoted class project (RemoteTest if you followed the above example)
]
using
System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
namespace RemotingTestServer {class TestServer {
[STAThread]
static void Main(string[] args) {
// Initialise a channel on port 8085
TcpChannel chan = new TcpChannel(8085);// Register the channel so the client can use it
ChannelServices.RegisterChannel(chan);// Register the class (aka Type) so the the client can use it
// The parameters for RemotingConfiguration.RegisterWellKnownType are:
// Full Type Name of object followed by comma followed by Assembly (dll) name
// (e.g. "ServerClassValue.HelloServer, RemoteTest")
// Object Endpoint name (used by client to request the object in the URI)
// Object Mode (from WellKnownObjectMode enums)
Type objType = Type.GetType("DavesRemoteObject.DaveMath, RemoteTest");
RemotingConfiguration.RegisterWellKnownServiceType(
objType,
"DaveMathEndPoint",
WellKnownObjectMode.SingleCall);// Prevent the server shutting down till we are finished with it
Console.WriteLine("Press <Enter> to terminate server");
Console.ReadLine();
}
}
}
The Client Project
[Again, project name does not matter, but again, make it a C# Console application so that we can easily output text. The required references are the same as for the server, i.e.:
System.Runtime.Remoting
The remoted class project (RemoteTest if you used the suggest name)
]
using
System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using DavesRemoteObject;namespace
RemotingTestClient {class TestClient {
[STAThread]
static void Main(string[] args) {
Console.WriteLine("Client\n======\n");
Console.WriteLine("Press <Enter> once server has started.");
Console.ReadLine();// Initialise the channel we'll use to talk to the server
TcpChannel chan = new TcpChannel();
ChannelServices.RegisterChannel(chan);// Do the maths locally first
DaveMath LocalDaveMath = new DaveMath();
ANumber number1 = new ANumber();
number1.Value = 2;
ANumber number2 = new ANumber();
number2.Value = 2;
Console.WriteLine("Local Math: 2 + 2 = " + LocalDaveMath.Add2ANumbers(number1, number2));
LocalDaveMath.WhereAmI();// Do the maths remotely
DaveMath RemoteDaveMath = (DaveMath) Activator.GetObject(
typeof(DaveMath), "tcp://localhost:8085/DaveMathEndPoint");
if (RemoteDaveMath == null) Console.WriteLine("Couldn't find server?");
else {
Console.WriteLine("Remote Math: 2 + 2 = " + RemoteDaveMath.Add2ANumbers(number1, number2));
RemoteDaveMath.WhereAmI();
Console.WriteLine("Method executed, check server window for 'WhereAmI' output.");
}// All done
Console.WriteLine("Press <Enter> to exit");
Console.ReadLine();
}
}
}