5.5 Calling Delegates Asynchronously

 <  Day Day Up  >  

A delegate can take a long time to return; you want to invoke the delegate asynchronously so that it returns immediately and notifies you when it has finished.


Technique

In addition to the delegate and the method to bind to that delegate, create a method that is used to process the results of the asynchronous method call. This method takes a single IAsyncResult parameter. This method is called when the delegate method has finished, and you can obtain results by calling the EndInvoke method obtained from the IAsyncResult object.

 
 class TearCallback {     public void PrintTearResult( IAsyncResult ar)     {         TearWebPage tear = (TearWebPage)((AsyncResult)ar).AsyncDelegate;         Console.WriteLine( "TearPage returned {0}", tear.EndInvoke( ar ) );     } } 

Before invoking the delegate, create an AsyncCallback object by passing the method name of the result method mentioned earlier. If this method is not static, use an instance of the object that implements this method followed by the dot operator ( . ) and the method name.

Listing 5.2 Asynchronous Delegates
 using System; using System.Threading; using System.Runtime.Remoting.Messaging; using System.Net; using System.IO; using System.Text; namespace _5_AsynchronousDelegate {      public delegate bool TearWebPage( string url );     class Class1     {         [STAThread]         static void Main(string[] args)         {             // create delegate attached to DoAsynchSleep method             TearWebPage tear = new TearWebPage( new WebTear().TearPage );             // create result class and create callback object             TearCallback result = new TearCallback();             AsyncCallback ascb = new AsyncCallback( result.PrintTearResult );             // invoke the delegate asynchronously             IAsyncResult ar = tear.BeginInvoke (                 "http://www.samspublishing.com", ascb, null );             // long operation here             Thread.Sleep(10000);         }     }     // Insert TearCallback implementation here     class WebTear     {         public bool TearPage( string url )         {             // final web page text variable             StringBuilder pageText = new StringBuilder("");             // create URI and a web request             Uri HttpSite = new Uri(url);             HttpWebRequest wreq = (HttpWebRequest)WebRequest.Create(HttpSite);             wreq.AllowAutoRedirect = true;             // get the stream associated with the web request             Stream webStream = wreq.GetResponse().GetResponseStream();             // create byte array for chunked data             byte[] webResponse = new byte[1024];             int bytesRead = 0;             do             {                 // read first 1024 bytes                 bytesRead = webStream.Read( webResponse, 0, 1024 );                 // append current chunk to final result                 if( bytesRead > 0 )                 {                     pageText.Append( Encoding.ASCII.GetString                         ( webResponse, 0, bytesRead ));                 }                 // continue until no more bytes are being read             } while( bytesRead > 0 );             // output final result             Console.WriteLine( pageText.ToString() );             return true;         }     } } 

To invoke the delegate asynchronously, call the BeginInvoke method defined in the delegate, passing the necessary delegate parameters followed by the AsyncCallback object and an optional object used to hold state information, as shown in Listing 5.2.

Comments

As fast as computers are nowadays, sometimes fast still isn't fast enough. Whether the lag occurs due to disk I/O, network traffic, or long computations , you can use this lag to your advantage by performing additional work until an operation finishes. Asynchronous method calls allow you to invoke a method and not wait for it to complete before you begin other tasks . As you work through the .NET Framework, you will see that you can perform asynchronous method calls in a variety of different ways. This recipe shows how to invoke a delegate asynchronously.

The initial code for the delegate is the same as the previous recipes in this chapter. The delegate is the same as well as its implementation and the code used to bind the two together. The difference is at the point where the actual work needs to happen, the point of delegate method invocation. The first recipe in this chapter mentioned that the delegate class generated upon using the delegate keyword contains three methods : Invoke , BeginInvoke , and EndInvoke . Up to this point, the Invoke method was called transparently anytime the delegate was used. Invoke performs a classic synchronous method call. In other words, Invoke does not return until the method has finished to completion. You use BeginInvoke and EndInvoke , however, when you want to call the delegate asynchronously.

The code listing for this recipe creates a class that contains a method implementation for the TearWebPage delegate. This method, TearPage , uses classes within the .NET Framework to open a connection with a remote Web server and request a page. If called synchronously, this method might not return for a while if network traffic is high, so we made the decision to call it asynchronously.

The first step, other than actually creating the delegate method implementation, of course, is to create a method used as the callback method. When the delegate method finishes, this method is called to notify the user of the delegate. The method itself accepts a single parameter whose data type is IAsyncResult . Before looking at the implementation of this method, you first have to understand how BeginInvoke works.

After you bind a method to a delegate, you have to set up the necessary objects used for the delegate callback. To do so, create an instance of the class that contains the callback method if this method isn't static. Next, create an AsyncCallback object passing the callback method name as the parameter. You can then call the BeginInvoke method. BeginInvoke is dynamically created based on the parameters. When you call BeginInvoke , as shown in the listing earlier, you provide each parameter necessary similar to the way you do if you were performing a synchronous method call. However, you need two additional parameters after the delegate parameter list. The first is the AsyncCallback method created earlier; the delegate class uses it when the method finishes. The final parameter can be any object that you want to create to hold state information. Because this parameter is optional and not used within the implementation of the BeginInvoke method itself, this parameter can be null . Once the BeginInvoke method is called, it returns immediately even though the method to which the delegate is bound has not finished. You can then perform additional processing as you wait for the delegate method to finish.

Once the delegate method finishes, your callback method created earlier is called. If you recall, this method receives a IAsyncResult parameter, which you can use to access the delegate instance that has finished. To do so, cast the IAsyncResult to an AsyncResult object and then cast the AsyncDelegate property of that object to your delegate class, as shown in the PrintTearResult method earlier. To access the return value, call the EndInvoke method defined in the delegate class. The EndInvoke is also dynamically created using the return value of the delegate method as its return value. Figure 5.4 shows the result of running Listing 5.2.

Figure 5.4. You download a Web page using an asynchronous delegate and access its result using the delegate callback method.

graphics/05fig04.jpg

 <  Day Day Up  >  


Microsoft Visual C# .Net 2003
Microsoft Visual C *. NET 2003 development skills Daquan
ISBN: 7508427505
EAN: 2147483647
Year: 2003
Pages: 440

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net