Programming Examples

Are you a Programmer or Application Developer or a DBA? Take a cup of coffee, sit back and spend few minutes here :)

Making Synchronous and Asynchronous Remote Call Via Delegate

1. Introduction to synchronous & Asynchronous Call

In this article, we will explore how one can use a delegate on the functions exposed by the remote objects. Also, we will see how do we call those remote object functions as synchronous and asynchronous. Basic knowledge on threading will help you catch this article in a better way but not a mandate. Below is a short note about synchronous and asynchronous function calls:

  1. When a function call is Synchronous, the client code that makes the call will wait for the completion of the call. Once the call returns it resumes executing the next statements exists after the call.
  2. When a function call is Asynchronous, the client function which makes the call will NOT wait for the completion of the called function. After calling the function, it soon starts executing the next statements.

2. About The Example

The Server in this example exposes a function which prints a running count by intentionally taking some time. One can think of this function as a long-running task on the Server.

The client is a Windows Form Application which has two buttons in it. One button is calling the remote function synchronously and other button does the same asynchronously. The client uses the delegate of the same type to make a call to the remote functions.

Our example has two running counts. One runs on the server and other one runs on the client application. The server displays the running count on the console window while client shows that in a text box. When we click the Start Sync button, the count will be running on the server and once it is finished, the count on the Windows Form starts. So, on this button click, the windows form will wait for the server to complete its counting before it starts its own counting. Here, we study how client makes Synchronous Remote Call to the server.

When we click the Start Async button, the count will run in parallel between a server and the calling client. This means, after the call the client will not wait for the server to complete its task. Here, we learn how the client can call same remote function Asynchronously. The below picture shows the application for this article:

Remoting Sync and Async Call - Example

Remoting Sync and Async Call – Example

3. Implementing Counter Remote Server

The code for the server is like this sites previous examples on Remoting. So you will not see much explanation here on the basics. If you need much explanation on the Remote Server, please have a look at the First Remoting article.

3.1 Namespace for Remoting

In the server, after creating the console project, we add a class called Counter and we derive it from MarshalByRef class. Then, we include the required name-space In the Counter.cs file. This Counter class will act as a Remote class.

//RemSrv 01: Include required assemblies
using System.Runtime.Remoting;

3.2 Counting Method of Remoting Server

The class has a constructor and a method ‘PerformCount’. This method is the Server’s Counting Task. We will call this counting from the client using delegates. Moreover, this is the method which we will call both Synchronous and Asynchronous way from the client. We will see about that when we are moving to the client-side coding. The code for this class is below:

//RemSrv 02: Initialize the remoting object
public Counter()
{
    Console.WriteLine("Remote Object Created. " + 
        Environment.NewLine);
}
 
//RemSrv 03: Perform the counting operation. This 
//will take sometime and is useful to explain How 
//async call to this method is useful from 
//the client end.
public void PerformCount()
{
    int x;
 
    for (x = 1; x < 10000; x++)
        Console.WriteLine("Current Count : " + 
            x.ToString());
 
    Console.WriteLine("Counting is finished");
    return;
}

3.3 Hosting Remote Server

In the application entry, we are hosting the remote object under the name ‘Counter’. For more detail look at the basic article given in the Remoting Section.

using System;
using System.Collections.Generic;
using System.Text;
 
//RemSrv 04 : Required Assemblies
using System.Runtime;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
 
namespace RemotingDelegate
{
 class Program
 {
  static void Main(string[] args)
  {
   //RemSrv 05 : Create a communication channel (Server) 
   //and register it
   TcpServerChannel SrvrChnl = new TcpServerChannel(13340);
   ChannelServices.RegisterChannel(SrvrChnl, false);
 
   //RemSrv 06 : Register the Remote Class so that the 
   //Object can go and sit on the Remote pool
   RemotingConfiguration.RegisterWellKnownServiceType(
    typeof(RemotingDelegate.Counter),
    "Counter", WellKnownObjectMode.SingleCall);
 
   //RemSrv 07 : Halt the server so that Remote client can 
   //access the object
   Console.WriteLine("Server is Running...");
   Console.WriteLine("Press Any key to halt the Server");
   Console.ReadKey();
  }
 }
}

4. Implementing the Client

The client is a windows application and section 2 of this article explains each user interface elements in it.

4.1 Namespace Required for Remoting Client

We include the below name-spaces in the Form class to access the Remoting and Thread function called ‘Thread.Sleep’. Also note that the project reference for the server also included. Once the server and client build without error, one can split the exes into the server and client machines for testing purpose.

//Client 01: Include the required namespace
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Threading;
using RemotingDelegate;

4.2 Delegate Declaration for Synchronous & Asynchronous Call

Once we are ready with the required name spaces, two delegates of the same are declared at the class level. One delegate is sufficient, but we kept two just to differentiate the way we will use it.

//Client 03: Declare delegates for Sync Call and Async Call
public delegate void SyncCall();
public delegate void AsyncCall();

4.3 Counting Task of Remoting Client

The ‘LocalCounter’ function here does the same job of the ‘PerformCount’ function on the server. So, here we simulate that there are two long running tasks, one at the server side and the other one at the client side. This function helps us to understand behavior of Synchronous & Asynchronous Remote call in relation to the local long-running task in the client.

//Client 06: Start the Local Counter. Assume that 
//It is a long running task.
private void LocalCounter()
{
    long x;
 
    lblDisplay.Text = "Starting the Local Count...";
 
    for (x = 1; x < 10000; x++)
    {
        txtCount.Text = x.ToString();
        Application.DoEvents();
    }
 
   lblDisplay.Text = "Local Count is Done.";
}

4.4 Calling Remote Function Synchronously

The click event handler for the button ‘Start Sync’ first creates the proxy for the remote object and stores that in a variable ‘cntObj’. Next, we create a delegate object of type SyncCall. We pass the function PerformCount to the delegate object by using the proxy ‘cntObj’. So, SyncCall delegate now points to the remote function PerformCount through the proxy here in the client. Once the delegate fnCounter is ready, we make a call to the remote function PerformCount using it. After this, a call to the local task (LocalCounter) also made. Note, the call made here is Synchronous. Below is the code:

private void btnSync_Click(object sender, EventArgs e)
{
    //Client 02: Get the Proxy for remote object
    Counter cntObj = (Counter)Activator.GetObject(
     typeof(Counter),
     "tcp://localhost:13340/Counter");
 
    //Client 04: Call the remote method through the 
    //delegate. This call is Synchronous.
    SyncCall fnCounter = new SyncCall(cntObj.PerformCount);
    fnCounter();
 
    //Client 05: Call the Local Counter
    LocalCounter();
}

Note that after making a call to the remote object using the delegate, the execution will pause at line 11 till the remote function finishes its task. Means, the LocalCounter call will wait for the Server to complete. Once the task is completed on the server, the execution resumes here on the client and calls the function LocalCounter. One can observe this by running the sample. First the console window on the server displays the running count. Once server completes its counting task, one can see the counter on the client form starts. The text box in the windows form renders this running count.

4.5 Delegate for Asynchronous Call

For making the asynchronous call, we create the delegate in the same way as we did in the previous step. But this time the delegate type is AsyncCall. Below is the code:

//Client 07: Create the proxy for remote Object and 
//set the delegate to the required remote function.
Counter cntObj = (Counter)Activator.GetObject(
 typeof(Counter), 
 "tcp://localhost:13340/Counter");
AsyncCall FnCounter = new AsyncCall(
 cntObj.PerformCount);

4.6 BeginInvoke Function and IAsyncResult Type

Once we create the delegate, instead of calling the function directly through it as we did before, we are using the BeginInvoke method on the delegate. The first parameter is a callback. On completion of task, the called remote function report back to the caller through this callback. As we are dealing with remoting, this is not covered here to avoid complexity. But this callback is handy for Non-Distributed applications. So, we are passing null for both the parameters. We store the return value in the IAsyncResult. This is to do a check on the Server operation to make a safe call on the EndInvoke.

//Client 08: Call the remote method through the 
//delegate. This is an Asynchronous call.
IAsyncResult AR = FnCounter.BeginInvoke(null , null);

4.7 Server Task and Client Task Running Asynchronously

After the above call, we are making a call to the local task. Here, the client after making a call to the PerfomCount using the BeginInvoke method on the delegate, immediately moves to the next statement. The next statement is a function-call for counting on the windows form. Unlike Synchronous call in Section 4.5, the client does not wait for the server to finish its counting.

//Client 09: Call the Local Counter. The Local Counter 
// also run in parallel.
LocalCounter();

4.8 Client Waiting for Server Task – IsCompleted of IAsyncResult

Finally, after making the call to both the client & server counting function to run simultaneously, we are waiting at the end of the routine to make a call to the EndInvoke. Note, this is a pair of its corresponding BeginInvoke. Remember, when we called the BeginInvoke function we stored the return value of type IAsyncResult in a reference called AR. Now, we use the IsCompleted Property of it to test the completion of the server’s task. Once we know the server is done with its task, we can make a call to EndInvoke safely by passing the instance of type IAsyncResult.

//Client 10: Test the Remote counting is finsihed or Not 
//before invoking the EndInvoke method on the delegate
while (!AR.IsCompleted)
    Thread.Sleep(500);
FnCounter.EndInvoke(AR);

The entire event Handling routine for the ‘Start Async’ button is shown below:

private void btnAsync_Click(object sender, EventArgs e)
{
 
    //Client 07: Create the proxy for remote Object and 
    //set the delegate to the required remote function.
    Counter cntObj = (Counter)Activator.GetObject(
     typeof(Counter), 
     "tcp://localhost:13340/Counter");
    AsyncCall FnCounter = new AsyncCall(
     cntObj.PerformCount);
 
    //Client 08: Call the remote method through the 
    //delegate. This is an Asynchronous call.
    IAsyncResult AR = FnCounter.BeginInvoke(null , null);
 
    //Client 09: Call the Local Counter. The Local Counter 
    // also run in parallel.
    LocalCounter();
 
    //Client 10: Test the Remote counting is finsihed or Not 
    //before invoking the EndInvoke method on the delegate
    while (!AR.IsCompleted)
        Thread.Sleep(500);
    FnCounter.EndInvoke(AR);
}

5. Screenshot of Synchronous and Asynchronous Call

In synchronous call, the Server runs its counter while client waits. In the console window one can see the running counts. After this count, one can see the count running on the client text box.

Dotnet Remoting Delegate called in synchronous way

Dotnet Remoting Delegate called in synchronous way

In asynchronous call, the client does not wait for the server to complete its task. So we will see counter running on the Server and Client simultaneously. One can observe this by looking at the running count in the console window and the text box of the client form. The below screen-shot explains this:

Dotnet Remoting Delegate called in Asynchronous way

Dotnet Remoting Delegate called in Asynchronous way

Source Code: Download Example From Google Drive

Categories: Remoting

Tags: , , ,

Do you like this Example? Share your thoughts!!

This site uses Akismet to reduce spam. Learn how your comment data is processed.