Parallelism in .NET – Part 20, Using Task with Existing APIs
Although the Task class provides a huge amount of flexibility for handling asynchronous actions, the .NET Framework still contains a large number of APIs that are based on the previous asynchronous programming model. While Task and Task<T> provide a much nicer syntax as well as extending the flexibility, allowing features such as continuations based on multiple tasks, the existing APIs don’t directly support this workflow.
There is a method in the TaskFactory class which can be used to adapt the existing APIs to the new Task class: TaskFactory.FromAsync. This method provides a way to convert from the BeginOperation/EndOperation method pair syntax common through .NET Framework directly to a Task<T> containing the results of the operation in the task’s Result parameter.
While this method does exist, it unfortunately comes at a cost – the method overloads are far from simple to decipher, and the resulting code is not always as easily understood as newer code based directly on the Task class. For example, a single call to handle WebRequest.BeginGetResponse/EndGetReponse, one of the easiest “pairs†of methods to use, looks like the following:
var task = Task.Factory.FromAsync<WebResponse>(
request.BeginGetResponse,
request.EndGetResponse,
null);
The compiler is unfortunately unable to infer the correct type, and, as a result, the WebReponse must be explicitly mentioned in the method call. As a result, I typically recommend wrapping this into an extension method to ease use. For example, I would place the above in an extension method like:
public static class WebRequestExtensions { public static Task<WebResponse> GetReponseAsync(this WebRequest request) { return Task.Factory.FromAsync<WebResponse>( request.BeginGetResponse, request.EndGetResponse, null); } }
This dramatically simplifies usage. For example, if we wanted to asynchronously check to see if this blog supported XHTML 1.0, and report that in a text box to the user, we could do:
var webRequest = WebRequest.Create("http://www.reedcopsey.com"); webRequest.GetReponseAsync().ContinueWith(t => { using (var sr = new StreamReader(t.Result.GetResponseStream())) { string str = sr.ReadLine();; this.textBox1.Text = string.Format("Page at {0} supports XHTML 1.0: {1}", t.Result.ResponseUri, str.Contains("XHTML 1.0")); } }, TaskScheduler.FromCurrentSynchronizationContext());
By using a continuation with a TaskScheduler based on the current synchronization context, we can keep this request asynchronous, check based on the first line of the response string, and report the results back on our UI directly.
How would it change if we need to add BeginGetRequestStream and send some data to the server before BeginGetResponse?
You would need to make a separate task for that pair (BeginGetRequestStream/EndGetRequestStream). You could do this task as a continuation on the first, however, to keep the entire series of operations asynchronous.
Hi reed,
It’s a long time since last time I read your blog, it’s still as always clean things up. Currently, I have met a problem with writing .net wrapper for native c++ code, and I get an Access vilation exception. It seems difficult for me to find the exact reason causing the issue due to lack of background in c++, and I see that you have deep background on both c++ and c#, so guess you might help me.
You can download my test application from my skydrive(http://cid-ff715505e131b476.office.live.com/self.aspx/.Public/SiftGPU.rar), and the solutions needs to be modified to use relative path to reference dlls to make it pass building process.
If you need any further information, please contact me via my mail.
Thank you.
Hi reed,
I am not sure whether you have looked into my issue. But I did solve it. Thanks anyway.
Task is a .Net 4.0 class, How would I do this in .Net 3.5 & Sharepoint 2010?
Sri,
Unfortunately, the Task class requires .NET 4. There is a back-port you can use that’s included with the Reactive Extensions framework. Installing that will allow the TPL to work on .NET 3.5sp1. You can download it here: http://msdn.microsoft.com/en-us/data/gg577610