Microsoft KB Archive/307546

= How to marshal an object to a remote server by value by using Visual C# =

Article ID: 307546

Article Last Modified on 5/9/2007

-

APPLIES TO


 * Microsoft Visual C# .NET 2002 Standard Edition
 * Microsoft Visual C++ .NET 2003 Standard Edition
 * Microsoft Visual C# 2005

-



This article was previously published under Q307546



For a Microsoft Visual Basic .NET version of this article, see 301116.

This article refers to the following Microsoft .NET Framework Class Library namespaces:
 * System.Runtime.Remoting
 * System.Runtime.Remoting.Channels
 * System.Runtime.Remoting.Channels.Tcp
 * System.Diagnostics

IN THIS TASK
SUMMARY
 * Requirements
 * Create the Remote Server Object
 * Create the Remote Server Application
 * Create the Client Application

REFERENCES



SUMMARY
This step-by-step article shows you how to marshal an object by value to a remote server. When you marshal an object by value, a copy of the object is created and serialized to the server. Any method calls that are made on that object are made on the server. Because the object needs to be serialized to the server, the class definition for the object that you are passing must be decorated with the [Serializable] attribute.

This article expands on concepts that are described in the following Microsoft Knowledge Base articles:

300951 How To Create a Remote Server by Using Visual Basic .NET

300943 How To Create Client Access to Remote Server by Using Visual Basic .NET

NOTE: These articles are not required 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, Microsoft Visual Studio 2005

This article assumes that you are familiar with the following topics:


 * Visual Studio .NET, Microsoft Visual Studio 2005
 * Basic networking

back to the top

Create the Remote Server Object
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 will be passed from the client to the server. This class is named ForwardMe. Because you want the ForwardMe class to be marshaled by value, you will decorate the ForwardMe class with the [Serializable] attribute.  Open Visual Studio .NET. Create a new Visual C# .NET Class Library application. Class1.cs is created by default.

Note In Visual C# 2005. Program.cs is created by default. In Solution Explorer, rename the file from Class1.cs to ServerClassValue.cs.  Open ServerClassValue.cs. Import the System.Diagnostics namespace so that you do not have to fully qualify names later in our code. using System; using System.Diagnostics;   Add two classes, HelloServer and ForwardMe. HelloServer inherits from the MarshalByRefObject class, and the ForwardMe class uses the  custom attribute. This tag enables the ForwardMe class to be streamed to and from the server, which occurs when you pass an object by value to a remote server.

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. Because ForwardMe does not inherit from MarshalByRefObject, it is passed by value to the server. public class HelloServer : MarshalByRefObject { }

[Serializable] public class ForwardMe { }                     Add a public method, 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 should now appear as follows: public class HelloServer : MarshalByRefObject {   public void HelloMethod(ForwardMe obj ) {          obj.CallMe; } }                    </li>  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 serializing the whole object to the server (marshal by value), the code runs in the server's process. [Serializable] public class ForwardMe {   public void CallMe {        Console.WriteLine(&quot;CallMe was executed in: &quot; +            Process.GetCurrentProcess.ProcessName.ToString); }                          }                    </li> Build the project to create the ServerClassValue.dll assembly.</li> Save and close the project.</li></ol>

back to the top

Create the 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. If you included the server object in this project, you cannot reference it because references can only be set to DLL files. <ol> Open Visual Studio .NET or Visual Studio 2005.</li> Create a new Visual C# .NET Console Application to start the remote server. Class1.cs is created by default.

Note In Visual Studio 2005, create a new Visual C# 2005 Console Application to start the remote server. By default, Program.cs is created.</li> In Solution Explorer, rename the file from Class1.cs to ServerObjectValue.cs.</li> Add a reference to the System.Runtime.Remoting namespace to the project.</li> Add a reference to the ServerClassValue.dll assembly that you created in the Create the Remote Server Object section.</li>  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; </li>  Declare the appropriate 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 Module1: TcpChannel chan = new TcpChannel(8085); ChannelServices.RegisterChannel(chan); </li>  Call the RegisterWellKnownType method of the RemotingConfiguration object to register the ServerClassValue object with the Remoting framework. You must specify the following parameters in the code: <ol style="list-style-type: lower-alpha;"> The full type name of the object that is being registered (which is ServerClassValue.HelloServer in this case) followed by the assembly name, ServerClassValue. You must specify both the name of the namespace as well as the class name. Because you did not specify a namespace in the previous section, the default root namespace is used.</li> The name of the endpoint where the object will be published. Clients need to know this name in order to connect to the object. Use RemoteTestValue.</li> 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.</li></ol>

RemotingConfiguration.RegisterWellKnownServiceType(   Type.GetType(&quot;ServerClassValue.HelloServer, ServerClassValue&quot;),    &quot;RemoteTestRef&quot;,    WellKnownObjectMode.SingleCall); </li>  Use the ReadLine method of the Console object to keep the server application running: Console.WriteLine(&quot;Press <ENTER> to exit...&quot;); Console.ReadLine; </li> Build your project.</li> <li>Save and close the project.</li></ol>

back to the top

Create the Client Application
<ol> <li>Open Visual Studio .NET.</li> <li>Create a new Console Application in Visual C# .NET. Class1.cs is created by default.

Note In Visual C# 2005, Program.cs is created by default.</li> <li>In Solution Explorer, rename the file from Class1.cs to ClientAppValue.cs.</li> <li>Add a reference to the System.Runtime.Remoting namespace to the project.</li> <li>Add a reference to the ServerClassValue.dll assembly that you created in the Create the Remote Server Object section.</li> <li> 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 ServerClassValue; </li> <li> Declare the appropriate variable to initialize a TcpChannel object that the client will use to connect to the server application. 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 object. Remember that this object will be passed by value. Add the declaration code in the Main procedure in Module1: TcpChannel chan = new TcpChannel; ChannelServices.RegisterChannel(chan); ForwardMe objForwardMe = new ForwardMe; </li> <li> 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: <ol style="list-style-type: lower-alpha;"> <li>The full type name of the object that is being registered (which is ServerClassValue.HelloServer in this case) followed by the assembly name, ServerClassValue. You must specify both the name of the namespace as well as the class name. Because you did not specify a namespace in the previous section, the default root namespace is used.</li> <li>The uniform resource identifier (URI) of the object that you want to activate. The URI must include the protocol (tcp), the computer name (localhost), the port (8085), and the endpoint of the server object (RemoteTestValue). To access the ServerClassValue remote server that is located on the local server, the URI is tcp://localhost:8085/RemoteTestValue.</li></ol>

HelloServer objHelloServer;

objHelloServer = (HelloServer)Activator.GetObject(       typeof(HelloServer),        &quot;tcp://localhost:8085/RemoteTestRef&quot;); if (objHelloServer == null) Console.WriteLine(&quot;Could not locate server&quot;); else {   //See next step }                    </li> <li> If the server object is instantiated successfully, call the server object's HelloMethod and pass in the newly created objForwardMe object.

Remember that the HelloMethod calls the CallMe method of the ForwardMe object, which displays the process name where the code is running to the console window. HelloServer objHelloServer;

objHelloServer = (HelloServer)Activator.GetObject(       typeof(HelloServer),        &quot;tcp://localhost:8085/RemoteTestRef&quot;); if (objHelloServer == null) Console.WriteLine(&quot;Could not locate server&quot;); else {   objHelloServer.HelloMethod(objForwardMe); Console.WriteLine(&quot;Method executed, check server window for output.&quot;); }                   </li> <li> Use the ReadLine method of the Console object to keep the client application running: Console.WriteLine(&quot;Press <ENTER> to exit...&quot;); Console.ReadLine; </li> <li>Build your project.</li> <li>Make sure that the server application is running.</li> <li>Run the client project to test the client-to-server communication.</li></ol>

When you run the client, you receive notification when the method has finished executing. Notice that the output from the CallMe method is displayed in the server's console window, not the client's. This is because you marshaled the object to the server by value.

back to the top

<div class="references_section">