RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Async-Up Your Objects : Page 2

Encapsulate asynchronous functionality directly into your business objects. The .NET Framework facilitates calling object methods asynchronously through the use of delegates. You may already know how to do this using helper code, but there is a cleaner and much cooler way of packaging this kind of functionality right inside your business objects.

Conventional Asynchronous Calling: A Refresher Course
First, make sure you import the two namespaces you will need: System, for the AsyncCallback delegate and System.Runtime.Remoting.Messaging, for the IAsyncResult interface and AsyncResult object.

Invoke makes a normal, or synchronous call, and BeginInvoke makes an asynchronous call and receives a couple of extra arguments, conforming to a naming convention used throughout the .NET Framework
Next, declare a delegate that defines the signature of the methods it will call. In this case, you're just worried about the one method, MoveFiles.

In C#:
public delegate bool MoveFilesDelegate(
      string origin, string destination);
Public Delegate Function MoveFilesDelegate( _
      ByVal origin As String, _
      ByVal destination As String) _
      As Boolean
I named the arguments of the delegate differently than in the actual method for two reasons. First, they can be called whatever you wish to call them; the delegate simply defines a signature, so the important part here is the data types, not the argument names. Second, you may want to build upon what you learn in this article and use this delegate for something else involving file moving. So origin and destination may not necessarily define folder locations, but they may very well be database tables, or FTP stores, or anything else for that matter.

From the client application, code the plumbing that takes care of firing the method asynchronously. First, instantiate the business object, as if you were going to make a normal synchronous call to any of its methods. Then instantiate the delegate into a variable and give it the method that you want to call with it. Remember, this method must have the same signature and return variable that the delegate defined.

In C#:
FileFunctions o_MyFunctions = new FileFunctions();
   MoveFilesDelegate o_MyDelegate = new
Dim o_MyFunctions As FileFunctions = _
      New FileFunctions
   Dim o_MyDelegate As MoveFilesDelegate = _
      New MoveFilesDelegate( _
   AddressOf o_MyFunctions.MoveFiles)
More often than not, you want to know when the method you are calling is finished executing. And of course, you may have requested something returned, as in the first example, where MoveFiles was called and returned a Boolean variable indicating success. In order to receive a notification of when the method is finished processing, you have to define a callback method. A callback method can be any method that conforms to the AsyncCallback delegate. The AsyncCallback delegate defines a void method, one that does not return anything, and with one argument of type IAsyncResult. The callback declaration is done in the same manner as you defined the function delegate above.

In C#:
AsyncCallback o_MyCallback =
      new AsyncCallback(MoveFilesComplete);
Dim o_MyCallback As AsyncCallback = _
      New AsyncCallback( _
   AddressOf MoveFilesComplete)
Note that as in the previous declaration, you are performing these tasks from a client application. Don't worry, all that will change later. You declared an instance of the AsyncCallback delegate and assigned it to point at a method called MoveFilesComplete. Unlike the MoveFilesDelegate variable you assigned before, this method has no object variable before it, so it resides within the client application itself. This need not be the case every time and you will explore this possibility further later in this article. You'll go on to the method code in a minute. First finish up the task of calling the MoveFiles method asynchronously by invoking it using the delegate you assigned to it.

In C#:
IAsyncResult o_AsyncResult = 
      "c:\\Folder1", "c:\\Folder2",
      o_MyCallback, null);
Dim o_AsyncResult As IAsyncResult = _
      o_MyDelegate.BeginInvoke( _
      "c:\\Folder1", "c:\\Folder2", _
      o_MyCallback, Nothing)
Notice that the first two arguments of this call are the arguments that the MoveFiles method is expecting. BeginInvoke automatically adjusts to accommodate however many arguments are expected by the method it is invoking. The next argument is the object you instantiated using the AsyncCallback delegate, which serves as a function pointer to MoveFilesComplete. The last argument is known as AsyncState and can contain anything you wish to put in it. This variable can later be retrieved from the callback routine.

Conventional Asynchronous Calling (continued)
The BeginInvoke method returns an implementation of the IAsyncResult interface. This object can be used to check the status of the asynchronous call to see whether or not it is still processing, as well as to block processing of the current thread (the thread that set up the asynchronous call) and wait for the completion of the invoked method. If you need to perform functionality like that, scope this object at the class level so you can access it outside the method that invoked the asynchronous call.

There are a couple of items to note about how you kicked off the asynchronous process. Upon executing this statement, the MoveFiles method fires and receives the arguments this line of code sends into it. The MoveFiles method fires and runs on a new thread so the client application where you executed it can regain control immediately. You don't have to wait until MoveFiles is finished processing: you have made an asynchronous call to MoveFiles.

The other important item of interest is the name of the method you just used, BeginInvoke. The delegate you declared also has a method called Invoke. You can use BeginInvoke to fire off the MoveFiles routine, but the call will not be made asynchronously. Instead you set a return variable, Boolean in this case, to the Invoke method and send only the arguments that MoveFiles is expecting. In this case, the client application waits until the processing that MoveFiles performs is finished before going to the next line of code.

I'm not discussing synchronous delegate calls in much detail here; the reason I brought it up is to point out the naming conventions used. Invoke makes the normal, or synchronous call, and BeginInvoke makes the asynchronous call and receives a couple of extra arguments. This naming convention is used throughout the .NET Framework to differentiate between synchronous and asynchronous invocation, and you will adopt it for your own business objects later in this article.

Other areas where this naming convention is used are in sockets programming and Web services. When you open a socket in a networking application, you can use a Receive method to receive the contents of a socket's buffer synchronously, or you can use a BeginReceive method to initiate the retrieval of a socket's buffer asynchronously. Later, you can use a callback method to wrap things up. Explaining this further is beyond the scope of this article, but you can see the resemblance.

Web services also use this naming convention for any methods you define as Web methods. Let's say you create a Web service with two Web methods called GetWeatherInfo and GetStockInfo. When you compile the Web service and consume it from a client application, the proxy object automatically adds four more methods to your service: BeginGetWeatherInfo, EndGetWeatherInfo, BeginGetStockInfo, and EndGetStockInfo. The "End" methods in both the sockets and Web service examples conform to the AsyncCallback delegate signature.

Now take a look at the callback method (which also conforms to the AsyncCallback delegate), MoveFilesComplete, and its contents.

In C#:
private void MoveFilesComplete(IAsyncResult ar)
      MoveFilesDelegate o_MyDelegate =
      bool b_Success = 
      // Perform any further functionality.
Private Sub MoveFilesComplete( _
      ByVal ar As IAsyncResult)
      Dim o_MyDelegate As MoveFilesDelegate = _
         CType(CType(ar, AsyncResult).AsyncDelegate, _
      Dim b_Success As Boolean = _
      ' Perform any further functionality.
   End Sub
The first thing to do in the callback method is to obtain an instance of the delegate variable that you declared in order to fire off the method in the first place. Remember o_MyDelegate? It's actually stored in the ar argument. The rather complex-looking line of code used to retrieve it actually breaks up into very simple pieces.

The line of code that retrieves the original delegate variable simply casts the ar variable as an AsyncResult object in order to obtain the AsyncDelegate property, and then casts the results as a MoveFilesDelegate. You need an instance of the original delegate so you can properly close the asynchronous call and retrieve a return variable, which is done in the second line of code. By calling EndInvoke and sending the ar variable you received in the callback routine, you close up the processing on the delegate and retrieve the Boolean return variable. A Boolean was the return type of the MoveFiles method as you designed it. However, in calling it using a delegate, you do not set anything to the method; instead you invoke it and then retrieve its results by way of the callback routine.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date