WebReference.com - Part 4 of Chapter 6: Professional C# Web Services, from Wrox Press Ltd (1/5) | WebReference

WebReference.com - Part 4 of Chapter 6: Professional C# Web Services, from Wrox Press Ltd (1/5)

Professional C# Web Services

Asynchronous Remoting

[The following is the conclusion of our series of excerpts from chapter 6 of the Wrox Press title, Professional C# Web Services.]

Calling remote methods across the network can take some time. We can call the methods asynchronously, which means that we start the methods, and during the time the method call is running on the server we can do some other tasks on the client. .NET Remoting can be used asynchronously in the same way as local methods.

Calling Local Methods Asynchronously

One way to do this is to create a thread that makes the remote call while another thread answers users' requests or does something else. It is a lot easier, however, to do it with the built-in support provided in the .NET Framework in the form of delegates. With delegates, threads are created automatically, and we don't have to do it ourselves.

First, let us look at an asynchronous example without calling remote methods.

In the sample class AsyncLocal we can see the LongCall() method, which takes some time to process. We want to call this method asynchronously:

using System;
using System.Threading;
namespace Wrox.Samples
{
   class AsyncLocal
   {
      public void LongCall()
      {
         Console.WriteLine("LongCall started");
         Thread.Sleep(5000);
         Console.WriteLine("LongCall finished");
      }

To make this method asynchronous we have to declare a delegate. The delegate must have the same signature and return type as the method that should be called asynchronously. The method LongCall() accepts no arguments and has a void return type, and the same is true for the defined delegate LongCallDelegate. With the keyword delegate the C# compiler creates a class that is derived either from Delegate or from MulticastDelegate, depending whether there is a return type or not. We can see this generated class by opening the generated assembly with the ildasm utility:

      private delegate void LongCallDelegate();
      public AsyncLocal()
      {
      }

In the Main() method we can now create a new instance of the class LongCallDelegate, and pass obj.LongCall. The constructor of the delegate class requires the target as an argument. We can look at the delegate as a type-safe, object-oriented function pointer. The object itself is passed with the method name of the function to the constructor:

      static void Main(string[] args)
      {
         AsyncLocal obj = new AsyncLocal();
         LongCallDelegate d = new LongCallDelegate(obj.LongCall);

Now we can start the method by calling BeginInvoke() on the delegate. Visual Studio .NET does not display this method with the IntelliSense feature because it is not available at the time of programming this method call; instead, it will be created as soon as we compile the project. The compiler creates three methods for the delegate class: Invoke(), BeginInvoke(), and EndInvoke(). Invoke() can be used to call the method synchronously, whereas BeginInvoke() and EndInvoke() are used to call the method asynchronously.

BeginInvoke() has two arguments in addition to the arguments that are declared with the delegate. With the first argument, an AsyncCallback delegate can be passed to this method. With the asynchronous callback, we can define a method with an IAsyncResult argument that will be called when the method is finished. In this sample, we pass null with both arguments, and put the returned reference to IAsyncResult into the variable ar:

         IAsyncResult ar = d.BeginInvoke(null, null);

The method call is started asynchronously. We can now doing something else in the main thread at the same time:

         Thread.Sleep(1000);
         Console.WriteLine("Main running concurrently");

As soon as we want to be sure that the asynchronous method completed (maybe we need some result from this method), the reference to the IAsyncResult interface can be used. With the IAsyncResult interface, we can check if the method is finished by checking the IsCompleted property. We can wait until the method completes by using the AsyncWaitHandle property and call WaitOne(). WaitOne() is a blocking call that waits until the method that belongs to the IAsyncResult is finished:

         ar.AsyncWaitHandle.WaitOne();
         if (ar.IsCompleted)
            d.EndInvoke(ar);
         Console.WriteLine("Main finished");
      }
   }
}

Created: April 8, 2002
Revised: April 8, 2002


URL: http://webreference.com/programming/csharp/webservices/chap6/4/