Asynchronous Programming has evolved over the years, right from the APM to the extremely powerful TAP Model. One (or probably the only one) of the problem which developers find themselves in is to use legacy code which were written somewhere in between the evolution. Quite often, developers might be inclined to wrap the existing code to the latest TAP model. How do one do that ? Let’s examine each model and its conversion one by one.
Asynchronous Programming Model
APM was the very first model introduced by the .Net designers, however it is no longer a recommended pattern. We will begin by writing an example code in APM, before figuring out how to convert it to TAP.
string filePath = @"yourfilepath"; byte[] buffer = new byte[20000]; using(FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, 1024, FileOptions.Asynchronous)) { Console.WriteLine(ReadFile(fs,buffer,0,buffer.Length)); } private int ReadFile(Stream fs, byte[] buffer,int offset,int count) { IAsyncResult result = fs.BeginRead(buffer, 0, count, null, null); int numBytes = fs.EndRead(result); return numBytes; }
The Task.Factory provides us an easy way to convert APM patterns to TAP. Let’s rewrite the above code in TAP now.
private Task<int> ReadAsync(Stream stream, byte[] buffer, int offset, int count) => Task<int>.Factory.FromAsync(stream.BeginRead, stream.EndRead, buffer, offset, count, null);
Event based Asynchronous Pattern
The second approach that Microsoft adopted was known as EAP. Let’s first examine a sample code for EAP.
Process p = new Process(); p.Exited += (e,args)=> { Console.WriteLine("Executing Exited Event"); Console.WriteLine($"Ended : {p.ExitTime}"); }; p.StartInfo.FileName = @"cmd"; p.EnableRaisingEvents = true; p.Start(); Console.WriteLine($"Started : {DateTime.Now}"); Console.WriteLine("Invoke Process completed");
The conversion from EAP to TAP is facilitated using the TaskCompletionSource class.
Console.WriteLine($"Ended : {InvokeProcess().Result}"); Task<string> InvokeProcess() { var tcs = new TaskCompletionSource<string>(); Process p = new Process(); p.Exited += (e,args)=>{ Console.WriteLine("Executing Exited Event"); tcs.SetResult("Result Data"); }; p.StartInfo.FileName = @"cmd"; p.EnableRaisingEvents = true; p.Start(); Console.WriteLine("Invoke Process completed"); return tcs.Task; }