Click here to Skip to main content
Click here to Skip to main content

.NET Remoting: Handling Remote Events Using Delegates – A Real World Example of 'Chat and File Send' Application

By , 14 May 2006
 

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.

Sample screenshot

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

Sample screenshot

Step 2

User ‘Vijiths’ logs in and sends a few messages and file to user ‘Joser’

Sample screenshot

Sample screenshot

Step 3

User ‘Joser’ gets a download-confirmation message

Sample screenshot

Sample screenshot

Sample screenshot

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.

Sample screenshot

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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

josekonoor
Web Developer
India India
Member
Pls visit my site at www.geocities.com/josekonoor
 
josekonoor@yahoo.com

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Questioncan any one help me to know how to send data to multiple systems using c#memberkoganti.pardhasaradhi16 Feb '10 - 4:43 
i am sending data to a single system but i need to send data to multiple systems can any one please do help me how i can do that please do send me saple code or implementation methodology
QuestionGreat Article - Wireless Internet VPN QuestionmemberMember 167710010 Mar '09 - 13:27 
Great Article
I have implemented a similar architecture as your one described here however am wondering weather you have tried this architecture over a Wireless Internet VPN connection?
 
I have founds that the system and architecture functions correctly when connected to the local LAN, however when connecting to the LAN through VPN on a wireless internet connection the broadcast appears to fail (events and delegates). The client can still obtain the data from the server via normal remoting calls, however the delegate broadcast event fails every time.
 
Any help would be greatfully apprieciated
 
Thanks Andrew
QuestionQuestion about dual channel approachmemberpmithila2 Aug '07 - 14:14 
Hi,
 
I went through your article and found it to be very relevant to what I am trying to do with remote events. I see that you have configured two channels one with a server-side starting point and with a client-side starting point.
 
I tried out the abstract class work-around you've suggested in my application with just one uni-directional server to client channel. It hasn't worked so far. I get a nasty remoting exception ("This remoting proxy has no channel sink which means either the server has no registered server channels that are listening, or this application has no suitable client channel to talk to the server.") even though I have attached an event handler to my remoted event.
 
Do you think having two channels is key to making remote events work or should it work with a uni-directional channel with the client not responding back to the server?
 
Thanks,
.net Newbie
 
.net Newbie
GeneralError with configuration filesmemberDiego F.10 May '07 - 6:07 
Hello. I'm trying to follow your example but I have an error with the configuration files.
 
I'm using vb.net 2005 and I can add but I can't add and other tags.
 
Do I have to configure something?
 
I have to specify that I can compile the project, there are information messages from the app.config.
 

 
Regards,
 
Diego F.

Generalsend filememberdj.rock29 Mar '07 - 23:41 
hi
can you send me a logic of function
 
OnFileSend(bytData, strFromUser, strToUser, strFileName)
 
waiting for your reply....
thanks.....
 
Regards,
 
DJ Rock

GeneralNice article. ThanksmemberFor God's sake. Let me register and be done with i4 Mar '07 - 8:06 
Thanks for the nice article and more importantly, the working sample. I've never dabbled much with remoting. It was very useful to compare with your code to pin point mistakes in my code.
Questionusing timer is efficient?memberdotnetpranker6 Feb '07 - 22:30 
i verified your code.Noticed that you have used a timer to get the updated messge from server or other clients..
I was in developing the same thing..but got stuck to pass message to form from the MessageshareCallbacks..I think using timer is not the right way..
Is there any way to pass the message from MessageshareCallbacks class to Form1 class..

AnswerRe: using timer is efficient?memberFor God's sake. Let me register and be done with i4 Mar '07 - 7:58 
There is a better way. You can bubble the event from the MessageshareCallbacks class which the Form1 class can hook up to.
 
Scott Stewart has an article on dotnetjunkies illustrating the technique.
http://dotnetjunkies.com/Tutorial/BFB598D4-0CC8-4392-893D-30252E2B3283.dcik

GeneralRe: using timer is efficient?membersaurabh99816 Apr '08 - 18:03 
i think so
GeneralRe: using timer is efficient?membersaurabh99816 Apr '08 - 18:05 
rdfgfgsdgsdg
GeneralTweakingmembersashisme5 Jul '06 - 3:57 
Just looked at the code. Looks good on most counts but don't you think notifying everybody when a single user recieves a file is a little inefficient??
I have written something similar but shied away from events for precisely this reason. My approach was a little like peer to peer. Once a client registers, his details (username, url) are sent to all clients by the server(notifications). The client then contacts the other clients directly.
When a client leaves, the server sends notifications to all connected clients.
But as a technology demonstrator your code does the job.
GeneralRe: TweakingmemberMarcelo R12 Nov '06 - 13:11 
Hi Sashisme,
 
Can you provide a sample of your approach?
 
thanks,
 
mrss
 
mrss

Questionoutside subnet?memberpointnetsolutions15 May '06 - 6:28 
How can you use this outside the subnet, dealing with routing tables and routers.
I have seen no free component allowing remoting to do this. further more, the model you suggest is a model, which microsoft and professionals do not recommend in production environments since it is event based.
AnswerRe: outside subnet?memberjosekonoor16 May '06 - 1:11 
This example is using tcp protocol and should work properly if you are using tcp network. Even if you are using sub nets and routers, tcp is offering a connected environment and the IP address can uniquely identify the machines across the sub nets. So, it should work (even though I have not tested it with sub nets.)
 
However, if you are using http protocol, then this example will not work as it is. Instead of tcp, you have to set http in the configuration file. Besides this, I don't think event handling will work as it is in http protocol.
 
I have not seen any comments against using events in remoting application with tcp protocol. Could you pls give me some more information or links where this info is available?
 
Thanks,
Jose Varghese
josekonoor@yahoo.com

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 14 May 2006
Article Copyright 2006 by josekonoor
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid