Using asynchronous method calls in C#
Customers hate to wait and are turned off by poor performance. .NET addresses this issue with asynchronous communication support. Get started with C#.
Using asynchronous method calls in C#
Customers hate to wait and are turned off by poor performance. .NET addresses this issue with asynchronous communication support. Get started with C#.
Several classes in the .NET Framework Base Class Library (BCL) provide both synchronous and asynchronous method signatures. Because a synchronous method call can create a delay in program flow, an asynchronous approach may be better in certain situations, such as when a program needs to send out requests to multiple Web services. This article will show you how to use asynchronous method calls for .NET development with C#.
The synchronous version of the Resolve method has the
following signature:
public static IPHostEntry Resolve( string hostName );
The IPHostEntry method accepts a single argument, the hostName, which can be either a DNS name (www.mydomain.com) or an IP address in dotted-quad notation (such as 10.10.14.2). It returns an IPHostEntry object. The IPHostEntry object members may be used to retrieve the host name, IP addresses, and other information related to this particular host.
You could use the Resolve method synchronously in your
program with code such as the following:
IPHostEntry host = Dns.Resolve(“10.10.14.2”);
Console.WriteLine(host.HostName);
The problem here is that as soon as Dns.Resolve is called, your program will block execution until the Resolve method completes its work and returns an IPHostEntry object, which may take several seconds. Since DNS resolution involves network access, this method call can potentially be affected by factors such as network latency and other issues that can delay operation and is thus well suited to the asynchronous approach.
In this scenario, the Web services used may be provided on networks with different degrees of latency and by various companies across the Internet. Consequently, the length of time required to complete a request is affected by several factors that are beyond your program’s control.
The asynchronous design pattern used in the .NET Framework is characterised by the use of BeginXXXX and EndXXXX methods, where XXXX is the name of the synchronous version of the method. Let's take a closer look at the asynchronous approach.
The BeginResolve method and IAsyncResult
To avoid blocking your program’s execution (as in the first
example), you can opt to use the asynchronous version of the
Resolve method: BeginResolve. This method has the following
signature:
public static IAsyncResult BeginResolve( string hostName,
AsyncCallback requestCallback, object stateObject );
When you call a method asynchronously, the call immediately
returns to your program, before the method being called has a
chance to finish (or sometimes even start). By definition, there
is no IPHostEntry object for the BeginResolve method to return,
so instead it returns a waitable object, the IAsyncResult
interface, which you can use later to retrieve the results of
the call. The IAsyncResult interface is defined as follows:
public interface IAsyncResult { object AsyncState {get;}
WaitHandle AsyncWaitHandle {get;} bool CompletedSynchronously
{get;} bool IsCompleted {get;} }
The second property in the IAsyncResult interface, the AsyncWaitHandle, can be used by your program to wait on the method to complete by passing it to one of the WaitHandle class’ methods, WaitAll, WaitOne, or WaitAny. This is useful if you are sending several asynchronous method calls to operate in parallel and would like to make sure they all complete before continuing your own program’s work, especially if your program’s continued operation is dependent upon the results of one or more of these calls.
The third property in the interface, CompletedSynchronously, returns a Boolean value indicating whether the method was able to be completed by the time the BeginResolve method returned.
The fourth property, IsCompleted, returns a Boolean value indicating whether the work being done by the method has completed. This is useful if you use a polling mechanism to determine whether the asynchronous call has completed.
Actually, there are four ways to make and complete .NET asynchronous calls. You can use polling (the IsCompleted property) or a callback delegate (discussed below), you can use the AsyncWaitHandle to wait on the call to complete, or can call the EndXXXX method yourself with the IAsyncResult returned from the BeginXXXX method and have it wait on the call to complete. The difference between these last two techniques is that if you perform the wait yourself (using the AsyncWaitHandle), you can “wake up” every now and then based on a timeout and decide at that point whether you really want to wait any longer.
EndResolve method and AsyncCallback delegate
One of the ways to complete an asynchronous method call is to
supply an AsyncCallback delegate to the BeginXXXX method. This
delegate has the following signature:
public delegate void AsyncCallback( IAsyncResult ar );
By providing a method in your program with this signature and
creating an AsyncCallback delegate pointing to that method, you
can have the asynchronous method call notify your program when
it has finished processing. The following code snippet shows how
you would call the Dns class BeginResolve method using a
callback:
AsyncCallback callback = new AsyncCallback(GetResult);
IAsyncResult ar = Dns.BeginResolve("10.10.14.2", callback,
null);
// Do some other work while the above finishes.
When the BeginResolve method finishes executing and has an
IPHostEntry object to return, it calls the delegate passed to it
allowing us to obtain the result. The following code shows how
the GetResult method in our program could be implemented:
private void GetResult(IAsyncResult ar)
{
IPHostEntry host = Dns.EndResolve(ar);
}
The Dns class calls the GetResult method when finished resolving the requested IP address, passing the same IAsyncResult interface that was returned from the initial call to BeginResolve. This allows us to call EndResolve using that argument to obtain the result of the call.
Summing up
Although you can use either synchronous or asynchronous method
calls in .NET, there are times when an asynchronous approach is
more efficient. This article has shown how to use asynchronous
method calls with C#. In a future article, I will show you how
to use the asynchronous design pattern to create your own
asynchronous methods for long-running operations.