Saturday 15 October 2011

Initiate with .Net Remoting


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:
  1. Client
  2. Remote Object
  3. 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.

 
 

No comments:

Post a Comment