How to marshal an object to a remote server by reference by using Visual C# (307600)



The information in this article applies to:

  • Microsoft Visual C# 2005
  • Microsoft Visual C# .NET (2002)

This article was previously published under Q307600
For a Microsoft Visual C++ .NET version of this article, see 818062.
This article refers to the following Microsoft .NET Framework Class Library namespaces:
  • System.Diagnostics
  • System.Runtime.Remoting
  • System.Runtime.Remoting.Channels
  • System.Runtime.Remoting.Channels.Tcp

IN THIS TASK

SUMMARY

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 How to create a remote server by using Microsoft Visual C# .NET

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.

back to the top

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
back to the top

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.
  1. Open Visual Studio .NET or Visual Studio 2005.
  2. Create a new Class Library application in C#. Class1.cs is created by default.

    Note In Microsoft Visual C# 2005, Program.cs is created by default.
  3. Rename the file from Class1.cs to ServerClassRef.cs.
  4. 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;
    					
  5. 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
    {
    }
    					
  6. 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();
    	}
    }
    					
  7. 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());
    	}
    								
    }
    					
  8. Build the project to create the ServerClassRef.dll assembly.
  9. Save and close the project.
back to the top

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.
  1. Open Visual Studio .NET or Visual Studio 2005.
  2. Create a new Console Application to start the remote server. Class1.cs is created by default.

    Note In Visual C# 2005, Program.cs is created by default.
  3. Rename the file from Class1.cs to ServerObjectRef.cs.
  4. Add a reference to the System.Runtime.Remoting namespace to the project.
  5. Add a reference to the ServerClassRef.dll assembly that you created in the Create a Remote Server Object by Passing Objects section.
  6. 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;
    					
  7. 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);
    					
  8. 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:
    1. 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.
    2. 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.
    3. 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);
    					
  9. Use the ReadLine method of the Console object to keep the server application running:
    Console.WriteLine("Press <ENTER> to exit...");
    Console.ReadLine();
    					
  10. Build your project.
  11. Save and close the project.
back to the top

Create a client to a remote server by passing objects

  1. Open Visual Studio .NET or Visual Studio 2005.
  2. Create a new Console Application. Class1.cs is created by default.

    Note In Visual C# 2005, Program.cs is created by default.
  3. Rename the file from Class1.cs to ClientAppRef.cs.
  4. Add a reference to the System.Runtime.Remoting namespace to the project.
  5. Add a reference to the ServerClassRef.dll assembly that you created in the Create a Remote Server Object by Passing Objects section.
  6. 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;
    					
  7. 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();
    					
  8. 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:
    1. 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.
    2. 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
    }
    					
  9. 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);
    }
    					
  10. Use the ReadLine method of the Console object to keep the client application running:
    Console.WriteLine("Press <ENTER> to exit...");
    Console.ReadLine();
    					
  11. Build your project.
  12. Make sure that the server application is running.
  13. 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.

back to the top

REFERENCES

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: back to the top

Modification Type:MinorLast Reviewed:10/4/2006
Keywords:kbChannels kbDiagnostics kbHOWTOmaster kbTunneling KB307600 kbAudDeveloper