This article demonstrates 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 calls back to
the object on the client. The only thing that is sent to the server is the
proxy, which marshals the callbacks to the client.
This article
expands upon concepts that are described in the following Microsoft Knowledge
Base articles:
307445
(http://support.microsoft.com/kb/307445/
)
How to create a remote server by using Microsoft Visual C# .NET
307739
(http://support.microsoft.com/kb/307739/
)
How to create client access to remote server by using Visual C# .NET
Note These articles are
not needed to complete the steps in this article.
Requirements
The following list outlines the recommended hardware, software,
network infrastructure, and service packs that you will need:
- Microsoft Windows 2000 Professional, Windows 2000 Server,
Windows 2000 Advanced Server, or Windows NT 4.0 Server
- Microsoft Visual Studio .NET or Microsoft Visual Studio
2005
This article assumes that you are familiar with the following
topics:
- Visual Studio .NET or Visual Studio 2005
- Basic networking
Create a remote server object by passing objects
The first step to create the server application is to create your
server object. Your server object is what the client application instantiates
and communicates with on the server computer. The client application does this
through a proxy object that is created on the client. Your server object, named
HelloServer, will reside in a Class Library (DLL). In the same project, you
also define the class that is going to be passed 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.
- Open Visual Studio .NET or Visual Studio 2005.
- Create a new Class Library application in C#. Class1.cs is
created by default.
- Rename the file from Class1.cs to
ServerClassRef.cs.
- Open the code file. Import the namespace System.Diagnostics so that you will not have to fully qualify names later in our
code.
using System;
using System.Diagnostics;
- Add two classes, HelloServer and ForwardMe, that both inherit from MarshalByRefObject. The HelloServer class is the main class that the client application uses. The ForwardMe class is used to send object data from the client to the server.
public class HelloServer : MarshalByRefObject
{
}
public class ForwardMe : MarshalByRefObject
{
}
- Add a public method, HelloMethod, to HelloServer that takes a ForwardMe object. You will use this method to pass a ForwardMe object to the server. This method calls the CallMe method of that object. Your HelloServer class should now appear as follows:
public class HelloServer : MarshalByRefObject
{
public void HelloMethod(ForwardMe obj )
{
obj.CallMe();
}
}
- Add a public method to the ForwardMe class, and name this method according to the process in which
this code is being executed. Because you are just sending a proxy stub to the
server and making call backs to the client (marshal by reference), the code
runs in the client's process.
public class ForwardMe : MarshalByRefObject
{
public void CallMe()
{
Console.WriteLine("CallMe was executed in: " +
Process.GetCurrentProcess().ProcessName.ToString());
}
}
- Build the project to create the ServerClassRef.dll
assembly.
- Save and close the project.
Create a remote server application
After you create the server object with which your client will
communicate, you must register this object with the Remoting framework.
Registering not only involves registering the object but also starting the
server and having it listen on a port for clients to connect. To do this, you
need 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. If you included the server object in this project, you
cannot reference it because references can only be set to DLL files.
- Open Visual Studio .NET or Visual Studio 2005.
- Create a new Console Application to start the remote
server. Class1.cs is created by default.
- Rename the file from Class1.cs to
ServerObjectRef.cs.
- Add a reference to the System.Runtime.Remoting namespace to the project.
- Add a reference to the ServerClassRef.dll assembly that you
created in the Create a Remote Server Object by
Passing Objects section.
- Use the using statement on the Remoting, Remoting.Channels, and Remoting.Channels.Tcp namespaces so you are not required to qualify declarations in
those namespaces later in your code. You must use the using statement before any other declarations:
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
- Declare a variable to initialize a TcpChannel object that listens for clients to connect on a certain port
(which is port 8085 in this case). Use the RegisterChannel method to register the channel that the client will use 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 Remoting framework. You must specify the
following parameters in the code:
- The full type name of the object that is being
registered (which is ServerClassRef.HelloServer in this case) followed by the assembly name ServerClassRef. You must specify both the name of the namespace as well as the
class name here. Because you did not specify a namespace in the previous
section, the default root namespace is used.
- The name of the endpoint where the object will be
published. Clients need to know this name in order to connect to the object.
For this example, use RemoteTestRef.
- The object mode, which 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. In the case of 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
once. Alternately, Singleton objects are created only once, and all clients communicate with
the same object.
RemotingConfiguration.RegisterWellKnownServiceType(
Type.GetType("ServerClassRef.HelloServer, ServerClassRef"),
"RemoteTestRef",
WellKnownObjectMode.SingleCall);
- Use the ReadLine method of the Console object to keep the server application running:
Console.WriteLine("Press <ENTER> to exit...");
Console.ReadLine();
- Build your project.
- Save and close the project.
Create a client to a remote server by passing objects
- Open Visual Studio .NET or Visual Studio 2005.
- Create a new Console Application. Class1.cs is created by
default.
- Rename the file from Class1.cs to
ClientAppRef.cs.
- Add a reference to the System.Runtime.Remoting namespace to the project.
- Add a reference to the ServerClassRef.dll assembly that you
created in the Create a Remote Server Object by
Passing Objects section.
- Use the using statement on the Remoting, Remoting.Channels, and Remoting.Channels.Tcp namespaces so that you are not required to qualify declarations
in those namespaces later in your code. You must use the using statement before any other declarations:
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using ServerClassRef;
- Declare a variable to initialize a TcpChannel object that the client will use to connect to the server
application. You must specify the port when you initialize the TcpChannel object to enable bidirectional communication. This is necessary
because you are marshaling an object by reference, and the server needs to use
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.
Secondly, you must initialize a new ForwardMe object that will be passed to the remote server. Add the
declaration code in the Main procedure in Class1:
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. You must specify the following parameters in the code:
- The full type name of the object that is being
registered (which is ServerClassRef.HelloServer in this case) followed by the assembly name ServerClassRef. You must specify both the name of the namespace as well as the
classname here. 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 need to 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
tcp://localhost:8085/RemoteTestRef URI to access the
ServerClass remote server.
HelloServer objHelloServer;
objHelloServer = (HelloServer)Activator.GetObject(
typeof(HelloServer),
"tcp://localhost:8085/RemoteTestRef");
if (objHelloServer == null)
Console.WriteLine("Could not locate server");
else
{
//See next step
}
- If the server object is instantiated successfully, you can
call the server object's method and pass in the newly created objForwardMe object. This should return the modified string, which you will
want to display.
HelloServer objHelloServer;
objHelloServer = (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 test the client-to-server
communication.
The output should appear in the client's console window.
Because you are marshaling by reference, callbacks are made to the
client.
For more information about the
TcpChannel class, visit the following Microsoft Web site:
For more information about the
RegisterWellKnownServiceType method, visit the following Microsoft Web site:
For an introduction to the Microsoft .NET Remoting Framework
(general .NET Development technical articles), visit the following Microsoft
Web site: