Microsoft KB Archive/301112

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

Article ID: 301112

Article Last Modified on 4/25/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 Q301112





For a Microsoft Visual C# .NET version of this article, see 307600.



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. The proxy marshals the call backs to the client.

This article is broken into three parts: The server object, the server application, and the client application. It 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 2000 Professional, Windows 2000 Server, 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:
 * Visual Studio 2005 or Visual Studio .NET
 * Basic networking

Create a remote server object by passing objects
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 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 marshaled by reference, the ForwardMe class must inherit from MarshalByRefObject.  Start Visual Studio 2005 or Visual Studio .NET. Create a new class library application and name it ServerClassRef . Rename the file Class1.vb as ServerClassRef.vb .  Open ServerClassRef.vb and add two classes called HelloServer and ForwardMe that both inherit from MarshalByRefObject. 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. Your ServerClassRef.vb code file should look like the following: Public Class HelloServer Inherits MarshalByRefObject

End Class Public Class ForwardMe Inherits MarshalByRefObject

End Class   Add a public method to HelloServer called HelloMethod that takes a ForwardMe object. You 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   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 just sending a proxy stub to the server and making callbacks to the client (marshal by reference), the code will execute in the client's process. Public Class ForwardMe Inherits MarshalByRefObject

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 ServerClassRef.dll assembly.</li> Close and save the project.</li></ol>

Create a remote server application
Now that you have created the server object that your client will communicate with, you must register this object with the Remoting framework. Registering not only involves registering the object but also includes 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 that 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> Start Visual Studio 2005 or Visual Studio .NET.</li> For simplicity's sake, create a new console application to start the remote server and name it ServerObjectRef .</li> Rename the file created by default from Module1.vb to ServerObjectRef.vb .</li> Add a reference to System.Runtime.Remoting namespace to the project.</li> Add a reference to the ServerClassRef.dll assembly that you 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 a variable to initialize a TcpChannel object that will listen for clients to connect on a certain port, in this case port 8085. Register the channel that 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> Register the ServerClassRef object with the 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 ServerClassRef.HelloServer, followed by the assembly name, ServerClassRef. 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> Next, provide 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 RemoteTestRef .</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 that is 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;ServerClassRef.HelloServer, ServerClassRef&quot;), _ &quot;RemoteTestRef&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> Build your project.</li> Close and save the project.</li></ol>

Create a client to a remote server by passing objects
<ol> <li>Start Visual Studio 2005 or Visual Studio .NET.</li> <li>Create a new console application and name it ClientAppRef .</li> <li>Rename the file created by default from Module1.vb to ClientAppRef.vb .</li> <li>Add a reference to System.Runtime.Remoting namespace to the project.</li> <li>Add a reference to the ServerClassRef.dll assembly that was created previously in this document.</li> <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> <li> 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 initializing the TcpChannel object to enable bidirectional communication. This is necessary because you are marshaling an object by reference and the server will need to make callbacks to the client. It will do so by using this port. The port should be different than the one that will be used to send data. 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. Add the declaration code in the Main procedure in Module1: Dim chan As TcpChannel = New TcpChannel(8086) ChannelServices.RegisterChannel(chan) Dim objForwardMe As New ServerClassRef.ForwardMe </li> <li>Now you can declare and instantiate the remote server. In this case, 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 ServerClassRef.HelloServer, 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.</li> <li> 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 URI &quot;tcp://localhost:8085/RemoteTestRef&quot; to access the ServerClass remote server. Dim objHelloServer As ServerClassRef.HelloServer

objHelloServer = CType(Activator.GetObject( _ Type.GetType(&quot;ServerClassRef.HelloServer, ServerClassRef&quot;), _ &quot;tcp://localhost:8085/RemoteTestRef&quot;), _   ServerClassRef.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 can call the server object's method, passing in the newly created objForwardMe object. The modified string should return as a result, so you will want to display that: Dim objHelloServer As ServerClassRef.HelloServer

objHelloServer = CType(Activator.GetObject( _ Type.GetType(&quot;ServerClassRef.HelloServer, ServerClassRef&quot;), _ &quot;tcp://localhost:8085/RemoteTestRef&quot;), _   ServerClassRef.HelloServer) If objHelloServer Is Nothing Then Console.WriteLine(&quot;Could not locate server&quot;) Else objHelloServer.HelloMethod(objForwardMe) 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 your project.</li> <li>Make sure the server application is running.</li> <li>Run the project and test the client-to-server communication. You should see the output displayed in the client's console window. You are marshaling by reference, so callbacks are made to the client.</li></ol>

<div class="references_section">