EAP (Event Asynchronous Pattern), helps to invoke a function in another thread which enables the current thread to continue. This can be achieved using Threads as well, but EAP helps to raise an event which alerts the client or caller sending the result or error while performing action etc…
Below code is sample to explain EAP, taking calculator as an example.
Performing “Sum” is an operation in “Calculator” class. This function can be called directly which is regular just like synchronous.
Calculator class also has an another method “SumAsync”, which is called sending the same arguments as like with “Sum” but an extra argument which can be used in the “Async” or helps to map the asyn response with the asyn request.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Threading;
using System.Collections.Specialized;
namespace Calculator
{
class Program
{
static void Main(string[] args)
{
Calculator objCalc = new Calculator();
//an event to observe when the sum operation gets completed
objCalc.OnSumCompleted += new EventHandler<SumCompletedEventArgs>(objCalc_OnSumCompleted);
//invoking the sum async function sending the appropriate user state
//Calling the async operations
objCalc.SumAsync(5, 8, new { Desc = "Sum of 5 and 8" });
//performing same asyn operations with same userstates to check
//if throwing dduplicate operation error
objCalc.SumAsync(5, 8, new { Desc = "Sum of 5 and 8" });
objCalc.SumAsync(4, 8, new { Desc = "Sum of 4 and 8" });
Console.Read();
}
static void objCalc_OnSumCompleted(object sender, SumCompletedEventArgs e)
{
//Checking if the operation has returened any error
if(e.Error==null)
//writing the result
Console.WriteLine(sender.GetType().InvokeMember("Desc",
System.Reflection.BindingFlags.GetProperty, null, sender, null) + " is " + e.Result);
else
//writing the error
Console.WriteLine("Error occured while performing "+sender.GetType().InvokeMember("Desc", System.Reflection.BindingFlags.GetProperty, null, sender, null) + "\n" + e.Error.Message);
Console.Read();
}
}
//Sum completed event arguments
public class SumCompletedEventArgs : AsyncCompletedEventArgs
{
public int Result;
public SumCompletedEventArgs(Exception exp, bool Cancelled, object UserState)
: base(exp, Cancelled, UserState)
{
}
}
//Calculator class which supports add operations in EAP and Synchronously
public class Calculator
{
//Hybrid dictionary for thread safe and adding the request tasks
HybridDictionary tasks = new HybridDictionary();
//delegate to invoke Sum Operation completed event
public delegate void SumCompletedEventHandler(SumCompletedEventArgs e);
//Event which gets fired when sum operation is completed
public event EventHandler<SumCompletedEventArgs> OnSumCompleted;
//Function which sums up given numbers.
//Sleep is included to observer asyn behaviour
public int Sum(int a, int b)
{
Thread.Sleep(2000);
return a + b;
}
//sum async method called sending "userstate" asn extra argument
public void SumAsync(int a, int b, object UserState)
{
AsyncOperation asyncOp = null;
try
{
//Checking if the request with given userstate is already in progress
lock (tasks.SyncRoot)
{
//creating async operation to track the async operation
asyncOp = AsyncOperationManager.CreateOperation(UserState);
if (tasks.Contains(UserState))
throw new Exception("User state is already in progress, duplicate operations cannot be performed");
tasks[UserState] = asyncOp;
}
//Invoking the function which sums up the values,
Action<int, int, AsyncOperation> objSumWorker = new Action<int, int, AsyncOperation>(SumWorker);
objSumWorker.BeginInvoke(a, b, asyncOp, null, null);
}
catch (Exception exp)
{
SumCompletedEventArgs e = new SumCompletedEventArgs(exp, false, UserState);
asyncOp.PostOperationCompleted(
(o) =>
{
if (OnSumCompleted != null)
OnSumCompleted(o, e);
}, UserState
);
}
}
private void SumWorker(int a, int b, AsyncOperation argAsync)
{
//creating an object for sumcompleted
SumCompletedEventArgs e = new SumCompletedEventArgs(null, false, argAsync.UserSuppliedState);
try
{
//finding the sum of given 2 numbers
e.Result = Sum(a, b);
//removing the request userstate from collection
lock (tasks.SyncRoot)
{
tasks.Remove(argAsync.UserSuppliedState);
}
//invoking anonymous function in asyn synchronisation context
argAsync.PostOperationCompleted
(
(o) =>
{
if (OnSumCompleted != null)
OnSumCompleted(o, e);
}, argAsync.UserSuppliedState
);
}
catch (Exception exp)
{
e = new SumCompletedEventArgs(exp, false, argAsync.UserSuppliedState);
}
}
}
}
No comments:
Post a Comment