Microsoft KB Archive/301116

= How to marshal an object to a remote server by value by using Visual Basic 2005 or Visual Basic .NET =

Article ID: 301116

Article Last Modified on 5/16/2007

-

APPLIES TO


 * Microsoft Visual Basic 2005
 * Microsoft Visual Basic .NET 2003 Standard Edition
 * Microsoft Visual Basic .NET 2002 Standard Edition

-



This article was previously published under Q301116





For a Microsoft Visual C# 2005 and Visual C# .NET version of this article, see 307546.



For a Microsoft Visual Basic 6.0 version of this article, see 266717.



SUMMARY
This article demonstrates 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 made on that object are done on the server. Because the object must be serialized to the server, the class definition for the object you are passing must be annotated with the  attribute. This article expands on 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

Requirements
The following list outlines the recommended hardware, software, network infrastructure, and service packs that you need:
 * Microsoft Windows Server 2003, Microsoft Windows XP, Microsoft Windows 2000 Professional, Microsoft Windows 2000 Server, Microsoft Windows 2000 Advanced Server, or Microsoft Windows NT 4.0 Server
 * Microsoft Visual Studio 2005 or Microsoft Visual Studio .NET

This article assumes that you are familiar with the following topics:
 * Microsoft Visual Basic 2005 or Microsoft Visual Basic .NET
 * Basic networking

Create the remote server object
The first step to creating the server application is to create your server object. The 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 will reside in a class library (DLL) and is called HelloServer. In the same project you will also define the class that is going to be passed from the client to the server. This class will be called ForwardMe. Because you want the ForwardMe class to be passed by value, you will annotate it with the  attribute.  Start Visual Studio 2005 or Visual Studio .NET. Create a new Visual Basic 2005 or Visual Basic .NET class library application and name it ServerClassValue . In Solution Explorer, rename the file created by default from Class1.vb to ServerClassValue.vb .  Open ServerClassValue.vb and add two classes called HelloServer and ForwardMe. HelloServer will inherit from MarshalByRefObject, while the ForwardMe class will use the   custom attribute. This tag will enable the ForwardMe class to be streamed to and from the server, which is what happens when passing an object by value to a remote server. The HelloServer class will be the main class used by the client application. The ForwardMe class will be used to send object data from the client to the server. Because ForwardMe does not inherit from MarshalByRefObject, it will be passed by value to the server. Your ServerClassValue.vb module should look like the following. Public Class HelloServer Inherits MarshalByRefObject

End Class  Public Class ForwardMe

End Class </li>  Add a public method to HelloServer called HelloMethod that takes a ForwardMe object. We will use this method to pass a ForwardMe object to the server. This method will call the CallMe method of that object. Your HelloServer class should now look like the following. Public Class HelloServer Inherits MarshalByRefObject

Public Sub HelloMethod(ByRef obj As ForwardMe) Dim i As Integer obj.CallMe End Sub End Class </li>  Add a public method to the ForwardMe class. This method will get the name of the process where this code is being executed. Because you are serializing the whole object to the server (marshaling by value), the code will execute in the server's process. <Serializable> Public Class ForwardMe

Public Function CallMe As Object Console.WriteLine(&quot;CallMe was executed in: &quot; & _       Process.GetCurrentProcess.ProcessName.ToString) End Function

End Class </li> Build the project to create the ServerClassValue.dll assembly.</li> Close and save the project.</li></ol>

Create the remote server application
Now that you have created the server object that your client will communicate with, you need to register this object with the Microsoft .NET 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 will output an executable file. The reason you included the server object in a separate project was so that you could easily reference the server object from the client. If you included it in this project you could not reference it, because references can only be set to DLL files. <ol> Open Visual Studio 2005 or Visual Studio .NET.</li> For simplicity's sake, create a new Visual Basic 2005 or Visual Basic .NET console application to start the remote server and name it ServerObjectValue .</li> In Solution Explorer, rename the file created by default from Module1.vb to ServerObjectValue.vb .</li> Add a reference to the System.Runtime.Remoting namespace to the project.</li> Add a reference to the ServerClassValue.dll assembly created in the previous section.</li>  Use the Imports statement on the Remoting, Remoting.Channels, and Remoting.Channels.TCP namespaces so you will not be required to qualify declarations in those namespaces later in your code. The Imports statement must be used prior to any other declarations. Imports System.Runtime.Remoting Imports System.Runtime.Remoting.Channels Imports System.Runtime.Remoting.Channels.TCP </li>  Declare the appropriate variable which will initialize a TcpChannel object that will listen for clients to connect on a certain port, in this case port 8085. Register the channel the client will use to communicate with the channel services by using the RegisterChannel method. Add the declaration code in the Main procedure in Module1. Dim chan As TcpChannel = New TcpChannel(8085) ChannelServices.RegisterChannel(chan) </li> Now register the ServerClassValue object with the .NET Remoting Framework by calling the RegisterWellKnownType method of the RemotingConfiguration object. You must specify the following pieces: <ol style="list-style-type: lower-alpha;"> The full type name of the object being registered, in this case ServerClassValue.HelloServer, followed by the assembly name, ServerClassValue. You must specify both the name of the namespace as well as the class name here. Since 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 final parameter specifies 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 will be created for each call made from a client, even if the same client calls the same method more than once. Singleton objects, on the other hand, are created once only and all clients communicate with the same object. RemotingConfiguration.RegisterWellKnownServiceType( _ Type.GetType(&quot;ServerClassValue.HelloServer, ServerClassValue&quot;), _ &quot;RemoteTestValue&quot;, _ WellKnownObjectMode.SingleCall) </li></ol> </li>  Keep the server application running by using the ReadLine method of the Console object. Console.WriteLine(&quot;Hit to exit...&quot;) Console.ReadLine </li> <li>Build the project.</li> <li>Save and close the project.</li></ol>

Create the client application
<ol> <li>Start Visual Studio 2005 or Visual Studio .NET.</li> <li>Create a new console application in Visual Basic 2005 or in Visual Basic .NET and name it ClientAppValue .</li> <li>In Solution Explorer, rename the file created by default from Module1.vb to ClientAppValue.vb .</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 earlier in this article.</li> <li> Use the Imports statements on the Remoting, Remoting.Channels, and Remoting.Channels.TCP namespaces so you will not be required to qualify declarations in those namespaces later in your code. The Imports statement must be used prior to any other declarations. Imports System.Runtime.Remoting Imports System.Runtime.Remoting.Channels Imports System.Runtime.Remoting.Channels.TCP </li> <li> Declare the appropriate variable which will initialize a TcpChannel object that the client will use to connect to the server application. Register the channel with the channel services by using the RegisterChannel method.

Secondly, you must initialize a new ForwardMe object that will be passed to the remote server object. Remember that this object is going to be passed by value. Add the declaration code in the Main procedure in Module1: Dim chan As TcpChannel = New TcpChannel ChannelServices.RegisterChannel(chan) Dim objForwardMe As New ServerClassValue.ForwardMe </li> <li>Declare and instantiate the remote server. You will instantiate the HelloServer object by using the GetObject method of the Activator object. You must specify the following pieces: <ol style="list-style-type: lower-alpha;"> <li>The full type name of the object being registered, in this case ServerClassValue.HelloServer, followed by the assembly name, ServerClassValue. 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.</li> <li> The Uniform Resource Identifier (URI) of the object 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 &quot;tcp://localhost:8085/RemoteTestValue&quot;. Dim objHelloServer As ServerClassValue.HelloServer

objHelloServer = CType(Activator.GetObject( _ Type.GetType(&quot;ServerClassValue.HelloServer, ServerClassValue&quot;), _ &quot;tcp://localhost:8085/RemoteTestValue&quot;), _   ServerClassValue.HelloServer) If objHelloServer Is Nothing Then Console.WriteLine(&quot;Could not locate server&quot;) Else 'See next step End If                       </li></ol> </li> <li> If the server object is instantiated successfully, you should call the server object's HelloMethod, passing 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 executing to the console window. Dim objHelloServer As ServerClassValue.HelloServer

objHelloServer = CType(Activator.GetObject( _ Type.GetType(&quot;ServerClassValue.HelloServer, ServerClassValue&quot;), _ &quot;tcp://localhost:8085/RemoteTestValue&quot;), _   ServerClassValue.HelloServer) If objHelloServer Is Nothing Then Console.WriteLine(&quot;Could not locate server&quot;) Else objHelloServer.HelloMethod(objForwardMe) Console.WriteLine(&quot;Method executed, check server window for output.&quot;) End If                   </li> <li> Keep the client application running by using the ReadLine method of the Console object: Console.WriteLine(&quot;Hit to exit...&quot;) Console.ReadLine </li> <li>Build the project.</li> <li>Make sure that the server application is running.</li> <li>Run the client project to test the client-to-server communication. When you run the client, you will receive notification when the method has finished executing. Notice that the output from the CallMe method was displayed in the server's console window, not in the client. This is because you marshaled the object to the server by value.</li></ol>

<div class="references_section">