<!-- Link to demo file download -->
Download demo project - 32 Kb
<!-- Add the rest of your HTML here -->
This article is a modest attempt to share the experience that I gained while going
through Microsoft’s article on Remoting and the documentation that has been
.NET SDK Beta 1. As I went along on my quest, I
found some interesting stuff on how Remoting works. I can say that things have
now started to make some sense. Then I looked at some of the samples that have been
provided with the SDK. The samples helped in implementing some basic stuff like
creating remote server objects and having a client access them. Interestingly,
there is a sample,
RemSpy, that is supposed to spy on the calls that are
made on a remote object. Looking at the code for RemSpy did not help make sense of things.
I ended up with a lot of questions. What is this object? Why is this derived from that
interface? why do I have to register some of the objects with Remoting services? So I
had to go down into the bowls of the Remoting architecture. It was an interesting and
worthwhile experience. Now I have some understanding of how the calls get moved from the
client to the server and then back. In this article I will not go into too much detail
about the basics. There are some nice articles by Microsoft that you can refer too for that.
Where To Look For The Basics
- Microsoft .NET Remoting: A Technical Overview
- .NET SDK Documentation
- Remoting Samples
Before I explain how this spy sample works, I will briefly explain how the Remoting
of calls work. The basic building block of communication between two applications is
the message object defined by the IMessage interface. In a very simple way this
communication can be described as follows:
- Application A creates a message envelope and puts all the information in that message.
- Then application A hands over the message envelope to a carrier.
- The carrier takes the message envelope over to application B.
- Application B opens the envelope, reads the message and takes the necessary action described by the message.
- If Application A is expecting a reply, then application B puts that information or reply in the message envelope.
- Application B hands over the envelop to the carrier.
- Finally, the carrier delivers the message back to application A.
Looking at the above flow, if we can intercept various calls, then we can see
inside the message envelopes and other related tasks.
How To Intercept The Calls
When a client creates a remote object, it is handed over an actual instance or a
proxy depending on the
AppDomain the client is running in. If the client is
running in an
AppDomain different than the server, it will be handed over
a proxy. Now, when the client makes a method call on the proxy, all the information is
packed in a message object,
IMessage. Then it is passed over to a message sink.
The message sink uses the channel to transport the message from the source to the destination.
When the server has to return the results, it does follows the same proces. The out parameters
or results are put in the message and sent to the message sink. Then the sink uses the channel
to propagate the results back to the source, i.e. the client. The whole mechanism is based on
sending a message from one message sink to another. Each message sink completes its work and
send the message to the next sink. If we can insert a sink in this chain of sinks, we can
intercept the calls and see what is being passed around at various stages of an operation.
.NET Remoting provides a couple of interfaces that can be used and extended to monitor
the calls to and from objects. Dynamic Properties and Dynamic Sinks are the two main
interfaces that help in intercepting the calls. What a server needs to do is register
a Dynamic Property. The Dynamic Property will implement the
The first parameter to the
RegisterDynamicProperty call is the DynamicProperty
that will be registered with the framework. The second parameter is the object for which the
property is registered. The last parameter is the context for which the property is registered.
Look in the documentation for more details on this call.
IContributeDynamicSink interface has only one method,
GetDynamicSink. This method is supposed to return the sink that will be
notified of Remoting calls made on the object. Therefore, in this method we will create
a sink and return it to the framework.
To provide our own sink, we will have to create a custom sink object derived from
It is this message sink object that helps in intercepting all the calls that are made to
and from the objects. This interface has only two methods,
ProcessMessageFinish. As the names signify, the sink is notified
when a message starts and finishes. The signature of these methods is very simple, they
have only three parameters.
The first parameter is the
IMessage object. If this is a MessageStart call
then this object contains the information sent from the client side. You can look at the
parameters and properties of the
IMessage object to see how the client has put
info into the message so that the stack can be recreated on the server side. The
IMessage object contains the properties like
Context, etc. From these
properties we can get all the details for the method call. If the call is MessageFinish then
the IMessage object contains the response from the server side. Again, we can peek inside the
message object to see how the server has returned the stack back to the client. The second
parameter tells whether the call is on the server or client side. And the last parameter tells
if the call is in asynchronous mode or not. The implementation of all these calls has been
provided in the source
How To Find Out When An Object Gets Marshaled And Unmarshaled
We can find out when an object gets marshaled, unmarshaled and disconnected. This
information is provided by
TrackingServices. We can register a tracking
TrackingServices to intercept these calls. We can provide our
own object to handle tracking. This is accomplished by creating a class derived from
This class has three methods that need to be implemented,
DisconnectedObject. These methods get
called when an object has been marshaled, unmarshaled and disconnected respectively.
We can simply dump the information of the
objects that get passed to these methods to see what information is contained in each.
To register the tracking handler, call the
RegisterTrackingHandler function on
trkHndlr = <span style='color:blue'>new</span>
When we are done with the tracking handler, unregister it from
Although the SDK documentation does not mention it, the
has not been implemented. When you call this function, an exception gets thrown saying that
this method is not implemented yet.
While going through various Microsoft Remoting samples, I came across various utility
functions that are very helpful in dumping information about Remoting objects. I have
modified these functions and added some more into a utility class. This class library
RemoteUtils is included with the source code for this article.
You will require this library to compile the server and client code included with this
article. The methods that are implemented by this utility lib are as follows.
DumpMessageObj - Dump IMessage Object Info
DumpObjectRef - Dumps ObjRef Info
DumpChannelObj - Dumps IChannel Object Info
DumpLeaseObj - Dumps ILease Object Info
Overtime I will be adding more functions into this utility class.
Source Code And Compilation
The source code for the server object is in
NKRemoteServer.cs. The client
application code is in
RemoteClientApp.cs. The utility library code is in
RemoteUtils.cs. The client configuration file is
This file needs to be copied to where ever you run the client. The project has been created using
VS.Net Beta 1. The main project file,
UtilServer.sln, is in the
UtilServer folder. Make sure that you start the server before you run the client.
Otherwise, an exception will be thrown by the client application. To test the sample, bring up
two DOS windows and start the server and client applications. You will see how the calls get
intercepted and all the information that gets emitted at various stages on the client as well as
the server side. It is really an interesting piece of information to watch. Most of the
implementation has been inspired by the
RemSpy sample included in the SDK. I have
extended this sample to spy on Proxy objects, also. I will be writing about that in a separate
article. If you want to run the server on a separate machine then change the
RemoteClient.cfg file’s entry in the
Believe me, it works. It is needless to say that you will require the .NET Framework
installed to compile and run these samples. The implementation has been done in