Thursday, March 13, 2008

Really Simple .NET Remoting Tutorial with VB.NET

So I've seen lots of examples of remoting on the net, this is not a new topic, but for some it can be a tough subject. Add to this the fact that many choose C# and some just want a good old VB sample so here goes for my longest post to date!!!

So what is remoting anyway
It lets you call objects located in different processes and on different machines just as though they were within the same application, much like when you call a .dll referenced by your app.

So you may say we can do this with WebServices, true, but here the requirement is that both client and server MUST reside on the .NET framework. So with the interoperability gone we get much better performance with a little more complexity.

How to go about it: Server side
First thing we have to do is make our class remoteable by inheriting from MarshalByRefObject.

Public Class clsRemoteObject
Inherits MarshalByRefObject

Public Function getRemoteString() As String
Return Now.ToString()
End Function

End Class

Make sure you put this code in a new class library project and call it: RemotingClassLib

This can then be hosted in any of the following:

  • Console (Must be started manually, but simple to administer)
  • Windows App (Must be started manually, but simple to administer)
  • ASP.NET Web App (Limited to HTTP, but you have session state, start up automatically etc)
  • Windows Service (Use Fast TCP comms, Start automatically but can e complex)

The host must then register a channel to accept incoming requests on. This is important! Most problems arise because of mis-configurations between client and server settings.

Now create another project in the same solution called ConsoleHost and chose the console Application type. Type any of these 3 in the Sub Main.

Create and register a TCP channel:
 Dim tcpChannel As IChannel
tcpChannel = New TcpServerChannel("8085")
ChannelServices.RegisterChannel(tcpChannel, False)
Same for an HTTP and now, new to .NET 2.0, IPC
 Dim  httpChannel As IChannel
httpChannel = New HttpServerChannel("8086")
ChannelServices.RegisterChannel(httpChannel, False)
 Dim  ipcChannel As IChannel
ipcChannel = New IpcServerChannel("Server")
ChannelServices.RegisterChannel(ipcChannel, False)

Next, hook up our remote class to the registered channel. Again you can use any of the following.

The type of object instantiation can also be controled in the hosting app:

  • Singleton: Good for multiple calls where server maintains object between calls and also state:
    RemotingConfiguration.RegisterWellKnownServiceType( _
GetType(RemotingClassLib.clsRemoteObject), "MyRemoteObject", _
WellKnownObjectMode.Singleton)
  • SingleCall: Good to keep overheads down 
    RemotingConfiguration.RegisterWellKnownServiceType( _
GetType(RemotingClassLib.clsRemoteObject), "MyRemoteObject", _
WellKnownObjectMode.SingleCall)
  • ClientSide Activation: Client controls activation and recieves a dedicated object.
    RemotingConfiguration.RegisterActivatedServiceType(  _
GetType(RemotingClassLib.clsRemoteObject))

That’s all for now on the server side, now to the calling client!

The Client Side
Here we must reference the Classlibrary that contains the class we wish to instantiate. Oh you say, that kind of negates the whole point because this will take a local copy, then if we update the class library we have a problem. Yes you are absolutely right but what you should do is create an interface in a separate assembly. Then implement that interface in your class library, after setting a reference to the interface library. Then you get the client remoting app to reference the interface also. This way your implementation code is not copied to the client. I’ll tweak the code at the end of this article, but for now let’s keep it simple. So with the reference we can instantiate the object, all we need is a line to redirect calls to methods on this object to the remote object, easy:

Private Sub Form1_Load(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Load

RemotingConfiguration.RegisterWellKnownClientType( _
GetType(RemotingClassLib.clsRemoteObject), _
"tcp://localhost:8085/MyRemoteObject.rem")

End Sub


Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click

Dim rs As New RemotingClassLib.clsRemoteObject
Me.Text = rs.getRemoteString()


End Sub

That’s it !!!!

No comments: