Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

About .NET Remoting: Three concepts Compared and Simplified

0.00/5 (No votes)
6 Apr 2005 2  
An article on .NET remoting which discusses and compares the three ways, by which .NET remoting can be used to access a Server-side object from the clients- Singleton, SingleCall and Client Activation.

Sample Image - AboutRemoting.gif

Introduction

In .NET Remoting, Singleton, SingleCall and Client Activation are the three different ways, which can be used to access a Server-side object on the client through MBR (MarshalByReference). This article uses a sample application which compares and simplifies these three concepts.

I have tried to limit the size of this article and focused on the main topic. Following are the introductions of these three concepts:

  1. Singleton: Same instance of a Server-side object is used by all the clients for all the requests.
  2. SingleCall: Whenever a new call is received, a new instance of the Server-side object is created and reference is passed to the client. Therefore, for each call to the server, the client gets a new instance of the object.
  3. Client Activation: In this, the Client requests to the server for creating a new instance which can be used for multiple calls. The instance activated by a client is not used by other clients. Client-Activated objects can store state information between method calls for its specific client.

Please note that you must derive that class from MarshalByRefObject, which is to be exposed to the clients to get the reference.

Singleton

As mentioned earlier, one Singleton object on the server is used by all the clients.

On the Server:

Mention the following settings in the "App.config" file.

<configuration>
   <system.runtime.remoting>
      <application name="MyRemoting">
         <service>
            <wellknown mode="Singleton" type="MyRemoteService.MyService, 
           MyRemoteService" objectUri="MyService.rem"/>
         </service>
         <channels>
            <channel ref="http" port="9999" />
         </channels>
      </application>
   </system.runtime.remoting>
</configuration>

In the above code, type contains the type of the object to be exposed on the server. objectUri is any specific name assigned to this object which will be used by the client while mentioning the server URL. Any specific port is specified for the channel to be used.

Include System.Runtime.Remoting and write the following block of code to configure these settings on the server.

RemotingConfiguration.Configure("MyRemoteServer.exe.config");

Please note that you will need to replace your config file name in place of "MyRemoteServer.exe.config" in the above statement, which will be your "AssemblyName.config".

On the Client:

Include System.Runtime.Remoting in your class and write the following code to create the proxy for the Singleton Server-side object.

MyService mySingletonRem = (MyService) Activator.GetObject(typeof(MyService),
     "http://localhost:9999/MyRemoting/MyService.rem");

URL mentioned above is like ProtocolUsed://ServerAddress:PortNumber/ApplicationName/ObjectUri

SingleCall

Whenever a new call is received, a new instance of the Server-side object is created and reference is passed to the client. Therefore, for each call to the server, the client gets a new instance of the object.

To create SingleCall objects, everything will be same as in case of Singleton objects as mentioned above, but mode specified in the App.Config file on the server, which will be "SingleCall" in place of "Singleton".

Client Activation

In this, the Client requests to the server for creating a new instance which can be used for multiple calls. The instance activated by a client is not used by other clients. Client-Activated objects can store state information between method calls for its specific client.

On the Server:

Mention the following settings in the "App.config" file.

<configuration>
   <system.runtime.remoting>
      <application name="MyRemoting">
         <service>
            <activated type="MyRemoteService.MyService, MyRemoteService" />
         </service>
         <channels>
            <channel ref="http" port="9999" />
         </channels>
      </application>
   </system.runtime.remoting>
</configuration>

On the Client:

Include System.Runtime.Remoting and System.Runtime.Remoting.Activation and write the following block of code.

object[] activateAttribute = 
              {new UrlAttribute("http://localhost:9999/MyRemoting")};
            
MyService myClientActivatedRem = 
              (MyService) Activator.CreateInstance(typeof(MyService), 
              null, activateAttribute);        

About Sample Application

The application creates all of the three types of objects of the same class. Although, in real time projects, we will rarely get a case to create all kinds of objects of the same class. I just created them for the same class to understand and compare them easily.

Each sample object maintains a counter of the number of Client calls received by it. It returns a message which includes that counter on calling a method ServeAll().

Each client creates proxies for all of the three kinds of Server-side objects on startup. There are three buttons in the client; i.e., "Singleton", "Client Activated" and "SingleCall". Clicking on the buttons, sends a call to respective kind of Server-side object. That means, on clicking "Singleton" button, client calls the method ServeAll of the "Singleton" object.

Running Sample Application

  1. To run the demo, unzip all the demo files to a folder. Now, you can see there are two folders, one is MyRemoteServer and the another one is MyRemoteClient.
  2. Now, start the server by executing the file "MyRemoteServer.exe" in the MyRemoteServer folder.
  3. Start a client by executing the file "MyRemoteClient.exe" in the MyRemoteClient folder.
  4. Start another client by executing the file "MyRemoteClient.exe".
  5. Now, click on the buttons "SingleCall", "Singleton" and "Client Activated", one-by-one on both the clients.
  6. You will notice the following results.
    • On clicking "SingleCall", the Server-side object will always say that "I have received 1 Client Requests so far.". Though, the number of SingleCall requests sent from the client increases on every click (This is reflected on the lower part of the window). This is due to the fact that each method call from the client is served by a new Server-side object in case of SingleCall objects.
    • On clicking "Client Activated", the Server-side object says that "I have received X Client Requests so far.", where X will be same as the number of ClientActivated requests sent from a particular client. That means, if first client has sent three requests to Client Activated object, that object will say "I have received 3 Client Requests so far.", no matter how many requests are sent by second client, as clients do not share their ClientActivated objects with other clients.
    • On clicking "Singleton", the Server-side object says that "I have received X Client Requests so far.", where X will be the sum of number of Singleton requests sent from all the clients. That means, if first client has sent three requests to Singleton object and second client has sent 6 requests, that Server-side object will say "I have received 9 (i.e. 3 + 6) Client Requests so far.". This is due to the fact that both of the clients share the same Server-side Singleton object.

Inside of the Sample Application

Following is Service class whose objects are exposed to the clients. Please note that it is derived from MarshalByRefObject.

using System;

namespace MyRemoteService
{
    /**********************************************************
        The objects of this class will be made available to 
        the clients thru .NET remoting. 
    **********************************************************/
    
    public class MyService: MarshalByRefObject
    {
        private int countRequests;

        //This method returns a message which includes the number of 

        //client requests received by the current instance of the class.

        public string ServeAll()
        {
            return "I have received " 
                + ++countRequests + " Client requests so far.";
        }
    }

}

The App.Config file on the server is shown below. See, it has entries for all the three types of objects. All of them are of same class i.e., MyRemoteService.MyService.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.runtime.remoting>
        <application name="MyRemoteService">
            <service>
                <wellknown
                    mode="Singleton"
                    type="MyRemoteService.MyService, MyRemoteService"
                    objectUri="MySingleton.rem"
                />
                <wellknown
                    mode="SingleCall"
                    type="MyRemoteService.MyService, MyRemoteService"
                    objectUri="MySingleCall.rem"
                />
                <activated
                    type="MyRemoteService.MyService, MyRemoteService"
                />
            </service>
            <channels>
                <channel ref="http" port="8989"/>
            </channels>
        </application>
    </system.runtime.remoting>
</configuration>

The server is written like this:

using System;
using System.Runtime.Remoting;

namespace MyRemoteServer
{
    /**********************************************************
        This class configures the channel to publish 
        the service thru .NET remoting
    ***********************************************************/

    class RemoteServer
    {
        /// <summary>

        /// The main entry point for the application.

        /// </summary>

        [STAThread]
        static void Main(string[] args)
        {
            RemotingConfiguration.Configure("MyRemoteServer.exe.config");

            Console.WriteLine("Listening for requests. Press Enter to exit...");

            Console.ReadLine();
        }
    }
}

The client has three member variables defined:

MyService myClientActivatedRem;
MyService mySingleCallRem;
MyService mySingletonRem;

The App.Config on the client is shown below:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <appSettings>
        <add key="MyRemoteSingletonServiceUrl" 
            value="http://localhost:8989/MyRemoteService/MySingleton.rem"/>
        <add key="MyRemoteSingleCallServiceUrl" 
            value="http://localhost:8989/MyRemoteService/MySingleCall.rem"/>
        <add key="MyRemoteClientActivatedServiceUrl" 
            value="http://localhost:8989/MyRemoteService"/>
    </appSettings>
</configuration>

The proxies are created on client load.

private void Client_Load(object sender, System.EventArgs e)
{

    //Initialize Singleton object proxy

    string mySingletonUrl = ConfigurationSettings.AppSettings
        ["MyRemoteSingletonServiceUrl"];
            
    mySingletonRem = (MyService) 
        Activator.GetObject(typeof(MyService), 
        mySingletonUrl);

    //Initialize SingleCall object proxy

    string mySingleCallUrl = ConfigurationSettings.AppSettings
        ["MyRemoteSingleCallServiceUrl"];
            
    mySingleCallRem = (MyService) 
        Activator.GetObject(typeof(MyService), 
        mySingleCallUrl);


    //Initialize ClientActivated object proxy

    string myClientActivatedUrl = ConfigurationSettings.AppSettings
        ["MyRemoteClientActivatedServiceUrl"];
            
    object[] activateAttribute = 
        {new UrlAttribute(myClientActivatedUrl)};        
            
    myClientActivatedRem = 
        (MyService) Activator.CreateInstance(typeof(MyService), null,
        activateAttribute);        

}

The click events of the three buttons have the following respective methods attached:

private void btnSendRequest_Click(object sender, System.EventArgs e)
{
    //Send a request to Singleton object


    //Increment and Refresh the number of requests 

    //to Singleton object

    lblSingleton.Text = ((int) ++requestSingletonCount).ToString();
            
    //Display the Response received from the server

    //from Singleton object 

    txtSingleton.Text = mySingletonRem.ServeAll();
}

private void btnSendSingleCallRequests_Click(object sender, System.EventArgs e)
{
    //Send a request to SingleCall object


    //Increment and Refresh the number of requests 

    //to SingleCall object

    lblSingleCall.Text = ((int) ++requestSingleCallCount).ToString();
            
    //Display the Response received from the server

    //from SingleCall object 

    txtSingleCall.Text = mySingleCallRem.ServeAll();        
}

private void btnClientActivated_Click(object sender, System.EventArgs e)
{
            
    //Send a request to ClientActivated object


    //Increment and Refresh the number of requests 

    //to ClientActivated object

    lblClientActivated.Text = ((int) ++requestClientActivatedCount).ToString();

    //Display the Response received from the server

    //from ClientActivated object 

    txtClientActivated.Text = myClientActivatedRem.ServeAll();        
}

Few Points to be mentioned

  • This article covers only MBR (MarshalByReference). MarshalByObject is not taken into account in this article.
  • Recycling of Server-side objects due to Lease-Expiry is not considered to leave the article simpler.
  • There are multiple ways to do what has been done. Only the method used in the Sample Application is mentioned in the article.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here