The Event-based Asynchronous Pattern (EAP) is a specific design pattern to standardize event-based asynchronous programming features. Such a design is available in multiple classes from .NET itself and is available and suggested in all our implementations if applicable.
Unlike the previously seen APM, in this pattern, any method that supports synchronous execution will add an overloaded method for an asynchronous invocation. The result, instead, will be available only to a specific predefined callback method, one for each available method, within the class itself.
Here is an example showing the WebClient
class downloading some web page data:
static void Main(string[] args) { //a simple web client var client = new WebClient(); //register for result callback client.DownloadDataCompleted += client_DownloadDataCompleted; //invoke asynchronous request client.DownloadDataAsync(new Uri("http://www.google.com")); Console.WriteLine("MAIN THREAD ENDED"); Console.ReadLine(); } static void client_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e) { //this callback receives the whole response (data and status) //data byte[] downloadDataResult = e.Result; //eventual exception Exception ex = e.Error; Console.WriteLine("Downloaded {0:N1}KB", downloadDataResult.Length / 1024d); }
The same features are available in any of our classes by implementing the same pattern. Here is an example:
class Program { static void Main(string[] args) { var instance = new SimpleAsyncClass(); Console.WriteLine("Sync value: {0}", instance.ProcessSomething()); //register an event handler to catch the result instance.ProcessSomethingCompleted += instance_ProcessSomethingCompleted; //invoke async invoke instance.ProcessSomethingAsync(); Console.WriteLine("MAIN THREAD ENDED"); Console.ReadLine(); } static void instance_ProcessSomethingCompleted(object sender, int e) { Console.WriteLine("Async value: {0}", e); } } public class SimpleAsyncClass { public int ProcessSomething() { Thread.Sleep(3000); //returns a random integer return DateTime.Now.Millisecond; } public void ProcessSomethingAsync() { //initialize a delegate object to make async call var invoker = new Func<int>(ProcessSomething); //start async elaboration with callback invoker.BeginInvoke(InnerProcessSomethingCompleted, invoker); } private void InnerProcessSomethingCompleted(IAsyncResult ar) { //catch the delegate object from async state var invoker = (Func<int>)ar.AsyncState; //raise the event with computed value if (ProcessSomethingCompleted != null) ProcessSomethingCompleted(this, invoker.EndInvoke(ar)); } //the event that is usable for intercepting the computed value public event EventHandler<int> ProcessSomethingCompleted; }
This simple implementation gives us the ability to understand how EAP works. The pattern asks us to add some naming conventions such as the syntax Async
at the end of the method or the syntax Completed
for the acknowledgement event.
The pattern itself, in its pure version, is more verbose than how it was just seen. It also requires a specific Delegate
declaration for each method (although all with the same sign), cancellation support, process state notification (the percentage or completion), and a busy indicator. It is at the discretion of the programmer whether to implement a pure pattern or a simplified one, as visible in the example just given.
The BackgroundWorker
is a component that supports a full EAP with the ability to run in an asynchronous way and synchronize the UI access by itself (discussed later in this chapter in the Task UI synchronization section).
3.133.158.32