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.

About Reed
Reed Copsey, Jr. - http://www.reedcopsey.com - http://twitter.com/ReedCopsey

Comments

8 Responses to “Parallelism in .NET – Part 20, Using Task with Existing APIs”
  1. How would it change if we need to add BeginGetRequestStream and send some data to the server before BeginGetResponse?

    • Reed says:

      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.

  2. zamesking says:

    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.

  3. Sri says:

    Task is a .Net 4.0 class, How would I do this in .Net 3.5 & Sharepoint 2010?

Trackbacks

Check out what others are saying about this post...
  1. [...] This post was mentioned on Twitter by Vicente Cartas, Reed Copsey, Jr.. Reed Copsey, Jr. said: Blog series on Parallelism in .NET Part 20, Using Task with Existing APIs http://bit.ly/bUhiHR #csharp #dotnet #TPL [...]

  2. [...] an asynchronous function.  Suppose, for example, that we wanted to do something similar to my asynchronous Task example – download a web page asynchronously and check to see if it supports XHTML 1.0, then report this [...]



Speak Your Mind

Tell us what you're thinking...
and oh, if you want a pic to show with your comment, go get a gravatar!