This step-by-step article describes how to marshal an object
by reference to a remote server. When you marshal an object by reference, the
runtime creates a transparent proxy so that the server can make callbacks to
the object on the client. Only the proxy is sent to the server. The proxy
marshals the callbacks to the client.
The first step to create the server application is to create your
server object. Your server object is what the client application creates an
instance of and what communicates with the server computer. The client
application communicates through a proxy object that is created on the client.
Your server object that is named HelloServer is located in a class library (DLL). In the same project, you
also define the class that you pass from the client to the server. This class
is named ForwardMe. Because you want the ForwardMe class to be marshaled by reference, the ForwardMe class must inherit from the MarshalByRefObject class.
Start Visual Studio .NET or Visual Studio 2005.
On the File menu, point to
New, and then click Project.
In Visual Studio .NET 2002, click Visual C++
Projects under Project Types, and then click
Managed C++ Class Library under Templates.
In Visual Studio .NET 2003, click Visual C++
Projects under Project Types, and then click
Class Library (.NET) under Templates.
In Visual Studio 2005, click Visual C++ under
Project Types, and then click Class Library
under Templates.
Name the project
ServerClassRef.
Open the ServerClassRef.cpp code file. Import the System.Diagnostics namespace so that you do not have to fully qualify names later in
your code.
#using <System.Dll>
using namespace System;
using namespace System::Diagnostics;
Add the HelloServer class and the ForwardMe class. Both classes inherit from MarshalByRefObject. The HelloServer class is the main class that the client application uses. The ForwardMe class sends object data from the client to the server.
__gc public class ForwardMe : public MarshalByRefObject
{
};
__gc public class HelloServer : public MarshalByRefObject
{
};
Note You must add the common language runtime support compiler option
(/clr:oldSyntax) in Visual C++ 2005 to successfully compile the whole code
sample. To add the common language runtime support compiler option in Visual
C++ 2005, follow these steps:
Click Project, and then click
<ProjectName> Properties.
Note <ProjectName> is a placeholder
for the name of the project.
Expand Configuration Properties, and
then click General.
Click to select Common Language Runtime
Support, Old Syntax (/clr:oldSyntax) in the Common Language
Runtime support project setting in the right pane, click
Apply, and then click OK.
For more information about the common language runtime
support compiler option, visit the following Microsoft Web site:
Add a public method that is named HelloMethod to HelloServer that takes a ForwardMe object. You use this method to pass a ForwardMe object to the server. This method calls the CallMe method of that object. Your HelloServer class appears as follows:
__gc public class HelloServer : public MarshalByRefObject
{
public:
void HelloMethod(ForwardMe* obj )
{
obj->CallMe();
}
};
Add a public method to the ForwardMe class, and name this method according to the process that runs
this code. Because you are sending a proxy stub to the server and making call
backs to the client (marshal by reference), the code runs in the process of the
client.
__gc public class ForwardMe : public MarshalByRefObject
{
public:
void CallMe()
{
Console::WriteLine("CallMe was executed in: {0}", Process::GetCurrentProcess()->ProcessName);
}
};
Build the project to create the ServerClassRef.dll assembly.
After you create the server object that your client communicates
with, you must register this object with the .NET Framework. Registering the
object also involves starting the server and communicating with the client. To
do this, you must have a project type that creates an executable. The server
object is included in a separate project so that you can easily reference the
server object from the client project.
Start Visual Studio .NET or Visual Studio 2005.
On the File menu, point to
New, and then click Project.
In Visual Studio .NET 2002, click Visual C++
Projects under Project Types, and then click
Managed C++ Application under
Templates.
In Visual Studio .NET 2003, click
Visual C++ Projects under Project Types, and
then click Console Application (.NET) under
Templates.
In Visual Studio 2005, click
Visual C++ under Project Types, and then
click CLR Console Application under
Templates.
Name the project ServerObjectRef,
and then click OK.
Open the ServerObjectRef.cpp code file. Use the following
code to add a reference to the System.Runtime.Remoting namespace.
Note To specify assembly search path, follow these steps:
Open the Property Pages dialog box for
the project.
Open the C/C++ folder.
Click the General tab.
Modify the Resolve #using References
property to the folder where the ServerClassRef.dll assembly exists.
Use the using statement on the Remoting, Remoting.Channels, and Remoting.Channels.Tcp namespaces so that you do not have to qualify declarations in
those namespaces later in your code. Use the using statement before any other declarations:
using namespace System;
using namespace System::Runtime::Remoting;
using namespace System::Runtime::Remoting::Channels;
using namespace System::Runtime::Remoting::Channels::Tcp;
Declare a variable to initialize a TcpChannel object that listens for clients to connect on a port (in this
sample, the port is 8085). Use the RegisterChannel method to register the channel that the client uses to
communicate with the channel services. Add the declaration code in the Main procedure in Class1:
TcpChannel* chan = new TcpChannel(8085);
ChannelServices::RegisterChannel(chan);
Call the RegisterWellKnownType method of the RemotingConfiguration object to register the ServerClassRef object with the .NET Framework. Specify the following parameters
in the code:
The name of the object that is registered.
The name of the endpoint where the object is published.
Clients must know this name to connect to the object. For example, use RemoteTestRef.
The object mode. This can be SingleCall or Singleton. This example specifies SingleCall. The object mode specifies the lifetime of the object when it is
activated on the server. For SingleCall objects, a new instance of the class is created for each call
that a client makes, even if the same client calls the same method more than
one time. However, Singleton objects are created only one time, and all clients communicate
with the same object.
Note To specify assembly search path, follow these steps:
Open the Property Pages dialog box for
the project.
Open the C/C++ folder.
Click the General tab.
Modify the Resolve #using References
property to the folder where the ServerClassRef.dll assembly exists.
Use the using statement on the Remoting namespace, the Remoting.Channels namespace, and the Remoting.Channels.Tcp namespace so that you do not have to qualify declarations in
those namespaces later in your code. Use the using statement before any other declarations:
using namespace System::Runtime::Remoting;
using namespace System::Runtime::Remoting::Channels;
using namespace System::Runtime::Remoting::Channels::Tcp;
using namespace ServerClassRef;
Declare a variable to initialize a TcpChannel object that the client uses to connect to the server application.
Specify the port when you initialize the TcpChannel object to enable bidirectional communication. You must do this
because you are marshaling an object by reference, and the server uses this
port to make callbacks to the client. The port should differ from the one that
is used to send data. Use the RegisterChannel method to register the channel with the channel services.
Initialize a new ForwardMe object that is passed to the remote server. Add the declaration
code in the Main function as follows:
TcpChannel* chan = new TcpChannel(8086);
ChannelServices::RegisterChannel(chan);
ForwardMe* objForwardMe = new ForwardMe();
Declare and instantiate the remote server. In this case,
use the GetObject method of the Activator object to instantiate the HelloServer object. Specify the following parameters in the code:
The full type name of the object that is registered (in
this example, it is ServerClassRef.HelloServer) followed by the ServerClassRef assembly name. Specify both the name of the namespace and the
name of the class. Because you did not specify a namespace in the previous
section, the default root namespace is used.
The uniform resource identifier (URI) of the object
that you must activate. The URI must include the protocol (tcp), the computer
name (localhost), the port (8085), and the endpoint of the server object (RemoteTestRef). Use the following URI to access the ServerClass remote server:
tcp://localhost:8085/RemoteTestRef
HelloServer* objHelloServer;
objHelloServer = static_cast<HelloServer*> (Activator::GetObject(
__typeof(HelloServer),
"tcp://localhost:8085/RemoteTestRef"));
if (objHelloServer == NULL)
Console::WriteLine("Could not locate server");
else
{
// see the next step
}
If the server object is instantiated successfully, you can
call the method of the server object and pass in the newly created objForwardMe object. This returns the modified string that you want to
display.
HelloServer* objHelloServer;
objHelloServer = static_cast<HelloServer*> (Activator::GetObject(
__typeof(HelloServer),
"tcp://localhost:8085/RemoteTestRef"));
if (objHelloServer == NULL)
Console::WriteLine("Could not locate server");
else
{
objHelloServer->HelloMethod(objForwardMe);
}
Use the ReadLine method of the Console object to keep the client application running:
Console::WriteLine("Press <ENTER> to exit...");
Console::ReadLine();
Build your project.
Make sure that the server application is running.
Run the project, and then test the client-to-server
communication.
The output appears in the Console window of the client. Because
you are marshaling by reference, callbacks are made to the client.
Note ServerClassRef.dll is located in the \ServerObjectRef\Debug and
the \ClientAppRef\Debug directories.