Introduction
.NET Remoting is a simple programming model/framework which allows objects from different machines/processes/app-domains to communicate with each other.
It allows the flexibility of using different types of communication protocols (TCP, HTTP, etc..) and message formatters (binary, SOAP, etc..). Communication among different
app-domains is facilitated by Remoting objects. Remoting objects can be hosted using Managed Executables/IIS/.NET Component Services. It is also possible for .NET applications
running on different machines to share the same instance of a Remoting object hosted on a server.
This document demonstrates how to handle events from a remote object using a real time ‘message and file transfer’ application.
Technologies covered in this document
This document demonstrates the following pattern and technologies:
- Publisher Listener Design Pattern
- Server activated singleton objects
- Marshal by reference remote object access
- Raising events from remote objects
- Use of binary format over TCP channel
Publisher-Listener Design Pattern
Design patterns are an efficient way of reusing and sharing solutions to repeating problems. ‘Publisher-Listener’ is a behavioral Design Pattern. It is also known
as ‘Observer’ pattern. By definition, a ‘Publisher-Listener’ pattern establishes a one-to-many dependency between objects so that when one object changes state,
all its dependents are notified and updated automatically.
As shown in the above diagram, in a ‘Publisher-Listener’ Design Pattern, when a publisher posts a message, all the listeners are automatically updated with the message.
A publisher and listener can be the same object. There can be so many publishers and listeners. All the listeners have to register to the server to enable
them to listen to the messages.
.NET Remoting terminologies
Server-activated objects
Server-activated objects are objects whose lifetimes are controlled by the server. They are created by the server only as needed when the client invokes the first
method on the object. Server-activated objects only support default constructors. To use a remote object with parameterized constructors, you can use client activation
or dynamic publication (see below). Server-activated objects are also referred to as well-known object types, as their location (URL) is published and known in advance.
There are two activation modes for server-activated objects, Singleton and SingleCall, both of which are described below.
SingleCall
SingleCall objects service one and only one request coming in. SingleCall objects are useful in scenarios where the objects are required to do a finite amount of work.
SingleCall objects are usually not required to store state information, and they cannot hold state information between method calls. However, SingleCall objects can
be configured in a load-balanced fashion.
Singleton objects
Singleton objects are those objects that service multiple clients and hence share data by storing state information between client invocations. They are useful in cases
in which data needs to be shared explicitly between clients and also in which the overhead of creating and maintaining objects is substantial.
For example, the following code snippet depicts a server-activated (well-known) type with activation mode set to SingleCall
.
<service>
<wellknown mode="SingleCall" type="Hello.HelloService, Hello"
objectUri="HelloService.soap" />
</service>
Client-Activated Objects (CAO)
Client-activated objects (CAO) are server-side objects that are activated upon request from the client. When the client submits a request for a server object using "new
"
operator or Activator.CreateInstance()
, an activation request message is sent to the remote application. The server then creates an instance of the requested class and returns
an ObjRef
back to the client application that invoked it. A proxy is then created on the client side using the ObjRef
. The client's method calls will be executed
on the proxy. Client-activated objects can store state information between method calls for its specific client and not across different client objects. Each invocation
of "new
" returns a proxy to an independent instance of the server type. For example, the following code snippet depicts a Client-Activated type. Note that we no longer need a URL,
as for client-activated types the type alone is sufficient for activation. Also, the well-known tag has been replaced by the activated tag.
<service>
<activated type="Hello.HelloService, Hello" objectUri="HelloService.soap" />
</service>
Types of marshalling
Objects are valid only in the application domain where they are created. Any attempt to pass the object as a parameter or return it as a result will fail unless
any of the following types of marshalling is used.
Marshal By Value (MBV)
For objects that are Marshal By Value (MBV), a complete copy of the object is made when the object is passed from one application to another. If the object is marked
as Serializable
, the object will automatically be serialized, transported from one application domain to the other, and then deserialized to produce an exact copy
of the object in the second application domain.
Marshal By Reference (MBR)
For objects that are Marshal By Reference (MBR), a reference to the object is made when passed from one application to another. When the object reference (ObjRef
) arrives
in the remote application, it is turned into a "proxy" back to the original object. In order to marshal a Remoting object by reference,
inherit it from the MarshalByRefObject
class.
Proxy objects
When a client creates an instance of a remote object, it receives a proxy to the class instance on the server. All methods called on the proxy will automatically
be forwarded to the remote class and any results will be returned to the client. From the client's perspective, this process is no different than making a local call.
Stateless and Stateful objects
The .NET Framework makes a provision for creating remote objects as stateless. When an object is configured as SingleCall, it will be created when a method is called on that object.
The object processes the call, returns an optional result, and is then collected by the garbage collector. This way, the client is always connected to a fresh object with each call.
Configuring an object as a Singleton ensures that all clients will be connected to the same object whenever a call is made to that object.
Lease based lifetime
The lifetime of remote objects is controlled by a leasing mechanism. When an object is first created, it is given a lease time. When the lease time of the object reaches zero,
the object will be disconnected from the Remoting infrastructure, and when all references to the object has been freed within the AppDomain, it will be collected by the garbage collector.
A number of mechanisms are provided that allow the client to extend the lease on the object, thereby sustaining its life.
Raising events from remote objects
As with any normal .NET class, event handlers can be attached to Remoting objects so that a client can hook methods to serve the declared events. Whenever the event gets fired
in the remote object, the event handler method is executed in the client. However, delegates require that the receiving object be able to obtain the type
information for the class whose function is being wrapped by the delegate. In the case of Remoting, it means that the client assembly be available to the server.
If the client assembly is not available to the server, that type information cannot be loaded.
To make remoted delegates work, an abstract class (MustInherit
in Visual Basic .NET, abstract
in C#) that contains the callback function must be defined
in a common assembly that both the client and server have access to. The client can then derive a custom class from this abstract class to implement the logic in the callback.
The abstract class needs to have a specific structure. The function to be used for callbacks must be a public function that cannot be overridden. This function must forward
all calls to a protected abstract function that is overridden in the derived client classes. The reason for this architecture is that the delegate needs to be able to bind
to a concrete implementation of the callback function, and this implementation must not be overridable.
Remoted delegates are implemented in the ‘Message and File Transfer Application’ (explained in section 6). You can refer the source code attached.
Message and File Transfer Application
Problem definition
Basically, it is a chat application for intranet users of a Windows network. The following screenshots explain the required functionality of this tool.
When a user executes the client application, the user gets automatically logged into the application. It then loads a WinForm with a list of all the users who have already
logged in. This list gets automatically updated in frequent intervals. In order to chat with a user, all that you have to do is to select the name of the user and type
the message on the editable textbox. On entering the message, it gets published to the remote object with the ‘from’ and ‘to’ addresses and all the listening clients get it.
On receiving a message, each client checks the ‘to’ address and decides whether to display that message or not.
Step 1
User ‘Joser’ logs in
Step 2
User ‘Vijiths’ logs in and sends a few messages and file to user ‘Joser’
Step 3
User ‘Joser’ gets a download-confirmation message
Solution architecture
The solution architecture is shown in the diagram below. There is class the object of which (the remote object) is hosted on a remote server by using a console application.
Loading of this application can be configured using a Windows service. As with any client-server application, it is a must that the server application should be up and running before
the clients can access it. This object is a singleton object. The client application is a WinForm which has reference to a local copy of the remote component.
Using the local reference, the client application creates a proxy object. This proxy object then gets a reference of the remote object so that whenever the clients access
the proxy object, it in turn accesses the remote object. Since the remote object is a singleton object, all the clients connecting to a single server accesses the same instance
of the remote class. This facilitates the communication among different clients.
The remote object exposes certain event handlers such as OnLogin
, OnLogout
, OnMessagePublish
, etc.. The client application can hook methods
to these event handlers. So whenever these events happen, all the clients get notified about it.
Whenever a user sends some message to another user, the OnMessagePublish
event is raised. The sender acts as a publisher. All the clients who have registered (added)
a method to the OnMessagePublish
event handler act as listeners. This is how the ‘Publisher-Listener’ Design Pattern is implemented in this design.
Configuration files
Server configuration file
<configuration>
<system.runtime.remoting>
<application>
<lifetime leaseTime="20D" sponsorshipTimeout="1H"
renewOnCallTime="1D" leaseManagerPollTime="1H" />
<service>
<wellknown
mode="Singleton"
type="MessageShare.SharedMessage,MessageShare"
objectUri="SharedMessage"/>
</service>
<channels>
<channel ref = "tcp" port = "8080">
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full" />
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>
Client configuration file
<configuration>
<system.runtime.remoting>
<application>
<lifetime leaseTime="20D" sponsorshipTimeout="1H"
renewOnCallTime="1D" leaseManagerPollTime="1H" />
<client>
<wellknown type="MessageShare.SharedMessage,MessageShare"
url="tcp://10.201.33.229:8080/SharedMessage" />
</client>
<channels>
<channel ref="tcp" port="0" clientConnectionLimit="20" >
</channel>
</channels>
</application>
</system.runtime.remoting>
<appSettings>
<add key="RemotingUrl" value="tcp://10.201.33.229:8080/SharedMessage"></add>
</appSettings>
</configuration>
Please remember to change the IP address and port number - tcp://10.201.33.229:8080 to that of the server machine where the server application is running. The port number
should be the same as that configured in the server configuration file.
Code snippets
Remoting class
Server application
Client application (WinForm)
Installation files
Installation notes
- Please remember to change the IP address and port number - tcp://10.201.33.229:8080 in the client configuration file to that of the server machine where the server application is running.
- The port number in the client configuration file should be same as that configured in the server configuration file.
- Manually start the server application (executable console application).
- Use the client application only after ensuring the following:
- The configuration files are updated properly.
- The server application is started.
Reference
Abbreviations
Abbreviation | Expansion |
MBV | Marshal By Value |
MBR | Marshal By Reference |
CAO | Client Activated Objects |
SOAP | Simple Object Access Protocol |
IIS | Internet Information Services |