.Net Remoting: the Quick and Dirty Guide

Are you studying for Exam 70-310 for MCSD or MCAD? Or has .Net Remoting given you The Fear?

The topic is much much easier than you think, so after studying the .Net Remoting section of Mike Gunderloy's excellent book (MCAD/MCSD Training Guide [70-310]) I've written a Quick and Dirty guide on the topic.

.Net remoting is a way of allowing two chunks of code talk to each other: across the room or across the world.

The first misconception to overcome is, as my boss put it 'But isn't that just Web Services?'

In short, while Web Services are Interoperable with many software vendors, languages and platforms, .Net remoting is Microsoft-Specific, and pretty much .Net specific as well.

And While Web Services must use Http, .Net remoting can use Http or Tcp, and it can be formatted as Binary or Soap. As such they can get a large performance boost over Web Services. Though I'd say they are trickier to write.

Why use .net remoting?

The reasons for .Net remoting are many, but they boil down to:

  1. You want to take a processing/memory load off the client's machines.
  2. There's hardware specific stuff that the clients can't do (e.g. you might have a Megatron Particle Accelerator and you want clients to be able to operate it. .Net remoting is your man!)
  3. You want to share data amongst a large number of clients. (e.g. you want clients to be able to look up data on your EmployeeGenePool database, without them having to individually host that database)
  4. You want your clients to be able to call some of your secret proprietary functionality but you don't want to give them the modules that perform this functionality. (And other control related reasons)
  5. You want to avoid redeploying your objects each time their functionality changes.
  6. Other. There's always an other.

So how do you go about it?

There's just a few important considerations really and after that it's just plug and play.

  1. Choose a Channel protocol. eg Tcp, Http.
  2. Choose a Formatter. eg, Soap, binary.
  3. Choose an Activation technique (ie choose an 'Architecture')
    1. Server activated (singlecall or singleton) (this is referred to as a WellKnown service/client type)
    2. Client activated (this is referred to as an Activated service/client type)

Implement .net Remoting in five minutes!

  1. On the Server:
    1. Create a Remotable Class
    2. Register a New Channel
    3. Register the Remotable Class
  2. On the Client
    1. Register a New Channel
    2. Register the Remotable Class
    3. Instantiate (and use) the Remote Class!

Alrighty. I'll go through each of those steps one at a time, and show you how it's done for each type of channel and activation.

Namespace warning: The following code assumes you've imported these namespaces (as required):

Imports System.Runtime.Remoting
Imports System.Runtime.Remoting.Channels
Imports System.Runtime.Remoting.Channels.Http and/or:
Imports System.Runtime.Remoting.Channels.Tcp 

On the server: Create a Remotable Class

First, create a Remotable Class. This is the class that your clients are going to be using.

A remotable class looks like any other class except it Inherits MarshalByRefObject. Also, the only constructor it has is the default constructor ("Public Sub New()"), unless it is Client-Activated, in which case it can have overloaded constructors

Class Person
Inherits MarshalByRefObject

'Example property
Private _Name As String
Public Property Name() As String
Get
Return _Name
End Get
Set(ByVal Value As String)
_Name = Value
End Set
End Property

'The default constructor
Public Sub New()
End Sub

'** Can only use this Overloaded Constructor if
' the class is going to be client activated!
Public Sub New(ByVal pName As String)
_Name = pName
End Sub
End Class

On the Server: Register a New Channel

We're going to write some Channel Registration code.

The following code can sit in the same project as your Remotable Class. That's the easiest way to do it - but not a good method if you're looking at remoting a lot of classes.

So preferably your Channel Registration code will sit in a separate project that acts as a "Remoting Server." The Remoting Server project will need to have a reference to the project that contains the Remotable Class.

(In practice your remoting server wouldn't have a reference to the remotable class, but rather a reference to an interface implemented by the remotable class. See the Extra Credit topic below for more on this practice.)

Where was I? Registering a new channel on the server. Here goes. For TCP do this:

'Register a New TCP Channel on port 1976
Dim channel As TcpServerChannel = New TcpServerChannel(1976)
ChannelServices.RegisterChannel(channel)

For HTTP do this:


'Register a new HTTP server channel on port 1976
Dim channel As HttpServerChannel = New HttpServerChannel(1976)
ChannelServices.RegisterChannel(channel)

On the server: Register the remotable class

For server activated (i.e. WellKnown) do this:

'**For SingleCall:
RemotingConfiguration.RegisterWellKnownServiceType(GetType(Person), _
"Person", WellKnownObjectMode.SingleCall)

'**For Singleton:
RemotingConfiguration.RegisterWellKnownServiceType(GetType(Person), _
"Person", WellKnownObjectMode.Singleton)

For client activated (ie, 'Activated') do this:

'Register the client activated object
RemotingConfiguration.RegisterActivatedServiceType(GetType(Person))

On the client: Register a New Channel

Note that the client code is similar to the host code, but you don't have to specify the port number (the host looks after this!)

For TCP channels...

'Register a new TCP client channel
Dim channel As TcpClientChannel = New TcpClientChannel()
ChannelServices.RegisterChannel(channel)

For HTTP channels...

'Register a new HTTP client channel
Dim channel As HttpClientChannel = New HttpClientChannel()
ChannelServices.RegisterChannel(channel)

On the client: Register the Remotable Class

Warning! This requires that the client project has a reference to the project containing the Remotable Class. Usually this is not only a security risk, but completely impractical. Instead the client project could reference an Interface implemented by the Remotable Class. See the Extra Credit section for further details.

Assuming we've established a reference to the remotable class (or an interface it implements), we are ready to Register the client's with the remoting server.

If it's a ServerActivated (i.e. 'WellKnown') type:

RemotingConfiguration.RegisterWellKnownClientType( GetType(Person), _
"tcp://localhost:1976/Person")

If it's a Client Activated (i.e. 'Activated') type:

RemotingConfiguration.RegisterActivatedClientType( GetType(Person), _
"tcp://localhost:1976")

On the client: Instantiate (and use) the remote class!

Now we can finally access the remotable class from the client. Before we proceed, let's take a moment to appreciate the technical marvel that is .Net remoting.

Somewhere out there, on the other side of the world perhaps, a class sits on a server. The class inherits MarshalByRefObject and it has been registered with a remoting server. Out here, on the client machine, we've fired off a message to tell that remoting server we wish to use the remotable class. Now, the way is cleared and we are able to use that class here on the client as if the code were held locally. Time and space are no match for .Net.

So let's invoke the server-hosted remotable class from the client.

The following works for all types of remote objects:

Dim lPerson as new Person()

'Now do something with the object...
lPerson.Name = "Fred"
Messagebox.Show("Hello " & lPerson.Name)

In the case of Client Activated objects, you also get the ability to call Non-default constructors, for example:

Dim lPerson as new Person("Fred")
Messagebox.Show("Hello " & lPerson.Name)

Extra Credit: Create an Interface for your class

In the infamous 'Real World' you can't allow the client to reference your server-side remotable class.

(Two sufficient reasons for this: If your class implements Secret Business Formulae then you don't want your client to decompile them, and secondly for versioning reasons you don't want to be blatting your remotable classes out to clients every time you make a change.)

Instead you create an interface, bundle that into an assembly and let the clients reference the interface assembly. Try decompiling *that* suckers. You won't find out a thing about our Secret Business Formulae! Your Remotable Class sits safely tucked away on the server, happily implementing the published interface.

Here's our example. First an interface, that will be made available to any clients:

Public Interface IPerson
Property Name()
End Interface

Now we change our remotable class so that it implements the IPerson interface:

Class Person
Inherits MarshalByRefObject
Implements IPerson
Private _Name As String
Public Property Name() As String Implements IPerson.Name
Get
Return _Name
End Get
Set(ByVal Value As String)
_Name = Value
End Set
End Property
Public Sub New()
End Sub

'** This Overloaded Constructor
' cannot be called from an interface!
' (nor from a server activated instance)
Public Sub New(ByVal pName As String)
_Name = pName
End Sub
End Class

On the client side replace all instances of 'Person' with 'IPerson' and you are then able to create the object without having a direct reference to it (only a reference to the interface it implements)

But this creates a new limitation for Client-Activated objects. The interface can't include constructors. So we can no longer call our non-default constructor. This is a real annoyance if you are into Non-Default Constructors. And you should be. In order to get around this limitation, Mike Gunderloy suggests we use a special pattern: The Class Factory.

Create an Interface to a Class Factory

A "Class Factory" is just a term used to describe a Class that creates and returns other classes.

Create a ClassFactory with one method for each of the constructors you want to call in your remotable class. In the example above we'd have an interface called IPersonFactory, which implements two methods: one for the default constructor and one for our overloaded constructor.

Public Interface IPersonFactory
Function CreatePerson()As IPerson
Function CreatePerson(ByVal pName As String)As IPerson
End Interface

Now create a remotable implementation of the IPersonFactory interface

Public Class PersonFactory
Inherits MarshalByRefObject
Implements IPersonFactory

Public Overloads Function CreatePerson() As IPerson Implements IPersonFactory.CreatePerson
Return New Person
End Function

Public Overloads Function CreatePerson(ByVal pName As String) As IPerson Implements IPersonFactory.CreatePerson
Return New Person(pName)
End Function
End Class

The Person Factory will act as a Server-Activated (i.e. WellKnown) singleton - because a single long-lived instance of it can be used to return as many Person objects as the clients desire.

On the client you create an IPersonFactory and use it to return the IPerson object you're after.

Conclusion

If you kept up with all that then bully for you. Mike's book gives a much better coverage, but takes seventy or so pages to cover what we've just covered. In the same chapter he also touches on using 'SoapSuds' to generate proxy classes, using IIS as the activation agent (rather than writing your own remoting server as we did), Leasing, Marshal by Value (explicit Serialization) and much more. I guess it's time to move on, I'd better get out the book and keep studying...

 

I'm currently writing a book about how to build your first product. If you want to build your first product, please sign up to be notified when the book is available.

(By the way, I read every comment and often respond.)

Your comment, please?

Your Name
Your Url (optional)
Note: I may edit, reuse or delete your comment. Don't be mean.