Introduction
.Net Remoting provides mechanism to communicate with object beyond the application context boundary. This application context known as AppDomain. It is a generic system for different applications to communicate with one another. Object exposes their processes called Remote methods for interprocess communication. Application might be hosted in same network or some remote location, either through intranet or Internet.
.Net remoting provides framework that allow objects to interact with each other across application domain. Remoting was designed in a way that it hides the most difficult aspects like managing connections, marshaling data, and reading and writing XML and SOAP. The framework provides a number of services, including object activation and object lifetime support, as well as communication channels which are responsible for transporting messages to and from remote applications.
Remote Object
Any object, outside the application domain of caller application called remote object. Local object that cannot be serialized cannot be passed to different application domain, hence cannot be remote object.
Any object can be changed into a remote object by deriving it from
MarshalByRefObject
, or by making it serializable either by adding the
[Serializable]
tag or by implementing the
ISerializable
interface. When a client activates a remote object, it receives a proxy to the remote object. All operations on this proxy are appropriately indirected to enable the Remoting infrastructure to intercept and forward the calls appropriately. In cases where the proxy and remote objects are in different application domains, all method call parameters on the stack are converted into messages and transported to the remote application domain, where the messages are turned back into a stack frame and the method call is invoked. The same procedure is used for returning results from the method call.
Here is a sample aplication for that. Each remoting application contains three parts:
- Client
- Remote Object
- Server.
Public Interface IObserver
Function InvokeMethod() As String
Function InvokeMethod(ByVal number1 As Integer, ByVal number2 As Integer, ByVal [operator] As Integer) As String
End Interface
Lets start with Remote object first. Here is an interface Iobserver that contains methods that’s are shared between the client and the server.
Public Class RemoteMyObject
Inherits MarshalByRefObject
Implements IDisposable
Public Sub New()
End Sub
Public Function Method1() As String
Method1 = Cache.CreateInstance.MyMethod1
End Function
Public Function Method2(ByVal number1 As Integer, ByVal number2 As Integer, ByVal [operator] As Integer) As String
Method2 = Cache.CreateInstance.MyMethod2(number1, number2, [operator])
End Function
Public Function Method3(ByVal clientId As Integer) As String
Method3 = Cache.CreateInstance.MyMethod3(clientId)
End Function
Private disposedValue As Boolean = False ' To detect redundant calls
' IDisposable
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
' TODO: free other state (managed objects).
Console.WriteLine("RemoteObject is Distroying")
End If
' TODO: free your own state (unmanaged objects).
' TODO: set large fields to null.
End If
Me.disposedValue = True
End Sub
#Region " IDisposable Support "
' This code added by Visual Basic to correctly implement the disposable pattern.
Public Sub Dispose() Implements IDisposable.Dispose
' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above.
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
End Class
Here is a sample Remote class, as we already discussed local objects that cannot be serialized cannot be remote object, so to make this class serializable we derived this from
MarshelByRefObject. You also noticed what is
Cached? It’s a single tone class that is define as below. Singletone class is a class that cannot be instanciate directly through constructor.
Public Class Cache
Private Shared _myInstance As Cache
Private Shared _Observer As Iobserver
Private Sub New()
End Sub
Public Shared Sub Attach(ByVal observer As IObserver)
_Observer = observer
End Sub
Public Shared Function CreateInstance() As Cache
If _myInstance Is Nothing Then
_myInstance = New Cache
End If
Return _myInstance
End Function
Public Function MyMethod1() As String
MyMethod1 = _Observer.InvokeMethod
End Function
Public Function MyMethod2(ByVal number1 As Integer, ByVal number2 As Integer, ByVal [operator] As Integer) As String
MyMethod2 = _Observer.InvokeMethod(number1, number2, [operator])
End Function
End Class
As per discussed instace of this class can be generated from CreateInstance() method. So this is first and most important part of our application. You might think why important? Because both client and server application use this objects for communication. You might think why don’t common class library project developed and distributed between client and server. Because it’s not a good programing practice to shared business logic to client side, that’s why we developed interface to hide bussiness intelegence.
Now lets design server side object. Remote server is console application that register Remote object as some well known service. Lets see how to do that. For this first develop remote class that implement Iobserver interface.
Imports System
Imports System.IO
Imports System.Runtime.InteropServices
Imports RemotableObject
Public Class MyObject
Implements IObserver
Implements Idisposable
Public Function InvokeMethod() As String Implements RemotableObject.IObserver.InvokeMethod
Console.WriteLine("Invoke 1 Method Called....")
InvokeMethod = "This is Invoke 1 Method"
End Function
Public Function InvokeMethod(ByVal number1 As Integer, ByVal number2 As Integer, ByVal [operator] As Integer) As String Implements RemotableObject.IObserver.InvokeMethod
Dim output As String = "Output: {0} {1} {2} = {3}"
Select Case [operator]
Case 1
output = String.Format(output, number1, "+", number2, (number1 + number2))
Case 2
output = String.Format(output, number1, "-", number2, (number1 - number2))
Case 3
output = String.Format(output, number1, "X", number2, (number1 * number2))
Case Else
output = String.Format(output, number1, "/", number2, (number1 / number2))
End Select
Console.WriteLine(output)
InvokeMethod = output
End Function
Private disposedValue As Boolean = False ' To detect redundant calls
' IDisposable
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
' TODO: free other state (managed objects).
Console.WriteLine("MyObject is Distroying")
End If
' TODO: free your own state (unmanaged objects).
' TODO: set large fields to null.
End If
Me.disposedValue = True
End Sub
#Region " IDisposable Support "
' This code added by Visual Basic to correctly implement the disposable pattern.
Public Sub Dispose() Implements IDisposable.Dispose
' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above.
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
End Class
As you see, we defined a class that implement Iobserver interface. Now develop console application that register this class as service. To register a service you have to define channel.
Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Channels
Imports System.Runtime.Remoting.Channels.Tcp
Imports RemotableObject
Module Module1
<STAThread()> _
Sub Main()
Dim RemoteMyObject As New RemoteMyObject
'************************************* TCP *************************************
' using TCP protocol
Dim channel As New TcpChannel(8080)
ChannelServices.RegisterChannel(channel, False)
RemotingConfiguration.RegisterWellKnownServiceType(GetType(RemoteMyObject), "RemoteObject.rem", WellKnownObjectMode.Singleton)
'************************************* TCP *************************************
Cache.Attach(New MyObject)
Cache.Attach(New MyClient)
Console.Out.WriteLine("Server is Ready to Accept Request")
While Console.Read()
Exit While
End While
End Sub
End Module
So here is our remote server is ready. When you run this application it will look like this.
Now last but not least start developing the client.
Imports RemotableObject
Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Channels
Imports System.Runtime.Remoting.Channels.Tcp
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
End Sub
Private Sub ExportButton1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ExportButton1.Click
'************************************* TCP *************************************
' using TCP protocol
' running both client and server on same machines
Dim chan As New TcpChannel()
ChannelServices.RegisterChannel(chan, False)
' Create an instance of the remote object
Dim remoteOITExport As RemoteMyObject
Try
remoteOITExport = TryCast(Activator.GetObject(GetType(RemoteMyObject), "tcp://dell6:8080/RemoteObject.rem"), RemoteMyObject)
OutputMessage.Text = OutputMessage.Text & vbCrLf & remoteOITExport.Method1
Catch ex2 As Net.Sockets.SocketException
MessageBox.Show(ex2.Message)
Catch ex1 As RemotingTimeoutException
MessageBox.Show(ex1.Message)
Catch ex As RemotingException
MessageBox.Show(ex.Message)
Finally
remoteOITExport = Nothing
ChannelServices.UnregisterChannel(chan)
chan = Nothing
End Try
End Sub
Private Sub ExportButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ExportButton.Click
'************************************* TCP *************************************
' using TCP protocol
' running both client and server on same machines
Dim chan As New TcpChannel()
ChannelServices.RegisterChannel(chan, False)
' Create an instance of the remote object
Dim remoteOITExport As RemoteMyObject
Dim number1 As Integer = New Random().Next(50, 99)
Dim number2 As Integer = New Random().Next(1, 49)
Dim [operator] As Integer = New Random().Next(1, 10)
Try
remoteOITExport = TryCast(Activator.GetObject(GetType(RemoteMyObject), "tcp://dell6:8080/RemoteObject.rem"), RemoteMyObject)
OutputMessage.Text = OutputMessage.Text & vbCrLf & remoteOITExport.Method2(number1, number2, [operator])
Catch ex2 As Net.Sockets.SocketException
MessageBox.Show(ex2.Message)
Catch ex1 As RemotingTimeoutException
MessageBox.Show(ex1.Message)
Catch ex As RemotingException
MessageBox.Show(ex.Message)
Finally
remoteOITExport = Nothing
ChannelServices.UnregisterChannel(chan)
chan = Nothing
End Try
End Sub
End Class
As you can see it’s a simple windows project having couple of buttons. On each button click channel is registered and client side proxy of remote object is generated through Activator.GetObject() method. Our user interface will look like this.
After pressing buttons for Remote Method 1 and Remote Method 2, output is generated on server side.