WCF Web API– Handling requests asynchronously

This is the ninth post on a series about the Preview 4 of WCF Web API. The previous posts were:

In this post, I show how to handle HTTP requests asynchronously.

.NET’s Asynchronous Programming Model (APM)

The first version of the .NET platform introduced the Asynchronous Programming Model (APM) to represent asynchronous operations. It is characterized by the following:

  • Each asynchronous operation is divided into two methods, the Begin method and the End method;
  • The Begin method receives the operation’s inputs and two extra parameters – an AsyncCallback and an object state. This method must return an IAsyncResult, representing the asynchronous operation.
  • The End method receives the above IAsyncResult and returns the operation result, waiting if it is not yet available

The APM model is used in several places of the .NET platform. Some examples are stream reading and writing; and asynchronous delegate invocation.

Currently, WCF also uses the APM model both on the client side and on the service side:

  • On the client-side, the generated proxies can expose each WCF operation as a Begin/End method pair.
  • On the service-side, the implementing class may expose a Begin/End method pair that will be called asynchronously by the WCF runtime.

The Preview 4 release of WCF Web API also supports this model. The following code excerpt shows an example of decomposing an Web API operation into a Begin and End methods

[OperationContract(AsyncPattern = true)]
[WebGet(UriTemplate = "image?uri={uri}")]
private IAsyncResult BeginGetImage(HttpRequestMessage req, string uri,
                                                 AsyncCallback ac, object state)
{
	...
}

private HttpResponseMessage EndGetImage(IAsyncResult ar)
{
	...
}

The usage of the asynchronous model is defined by the AsyncPattern property assigned with true on the OperationContract attribute.

More details about the AsyncPattern in “classical” WCF can be found in the following post series: WCF and the AsyncPattern property.

The Task-based model

The version 4.0 of .NET introduced a new asynchronous model based on the Task<T> class and TPL library. A Task<T> represents an asynchronous operation that returns a value of type T. On a first look, this class may seem similar to IAsyncResult, however there are significant differences:

  • No need to call an End operation to retrieve the result. Instead, this value can be obtained from the task itself.
  • Better support for cancellation, through cancellation tokens.
  • Better support for exception handling.
  • Native support for asynchronous operation composition, via the ContinueWith and the ContinueWhenAll/ContinueWhenAny methods.

The announced C#async support is also based on the Task<T> model and will provide a language integrated way of building and composing asynchronous operations.

In the .NET framework, this new Task<T> model is slowly replacing the APM model. For instance:

  • The new .NET’s HTTP client (HttpClient class) provides a set of XxxAsync methods, returning Task<HttpResponseMessage>, for performing asynchronous HTTP requests.
  • The WCF Web API message handlers, briefly described in the sixth post of this series, also use the new Task<T> model.

Using both asynchronous models

Unfortunately, the Preview 4 of WCF Web API doesn’t yet support the Task<T> model for the operation implementation. However, it is not hard to implement a APM based interface using Task<T>, as described in the following reference: TPL and Traditional .NET Asynchronous Programming. The key fact is that the Task<T> class also implements the IAsyncResult interface.

An example

To exemplify these concepts, the following example shows a service for image transcoding. It has one operation, that handles GET requests on the following URI template “image?uri={uri}”, and performs the following actions:

  • GETs the representation of the resource (an image) identified by the {uri}
  • Tries to build a bitmap with this resource’s representation
  • Encodes and returns the bitmap using the JPEG format

Obtaining the response to the GET request and all the associated representation bytes may take a significant time. In order to avoid keeping a thread blocked during this time, this operation’s implementation will be asynchronous.

private HttpResponseMessage _response;
private HttpResponseException _exception;

[OperationContract(AsyncPattern = true)]
[WebGet(UriTemplate = "image?uri={uri}")]
private IAsyncResult BeginGetImage(string uri, AsyncCallback ac, object state)
{
    Trace("BeginGet...");
    var task = Task.Factory.Iterate(GetImageAndConvertItToJpeg(uri), state);
    task.ContinueWith(t =>
        {
         Trace("Main task completed, calling callback");
         if (ac != null) ac(task);
        }, TaskContinuationOptions.ExecuteSynchronously);
     return task;
}

private HttpResponseMessage EndGetImage(IAsyncResult ar)
{
    Trace("...EndGet");
    var task = ar as Task;
    if (task == null || task.IsFaulted)
    {
        throw new HttpResponseException(HttpStatusCode.InternalServerError);
    }
    if (_exception != null) throw _exception;
    return _response;
}

The previous code excerpt presents the BeginGetImage and EndGetImage methods.

Regarding the Begin method:

  • The operation core processing is started on line 9, using a iterator based technique described in the following section, and is represented by a task.
  • On line 10, a continuation is added to the above task, so that the WCF callback is called when the task completes. This will trigger the call, by the WCF runtime, of the EndGetImage method.
  • On line 15, the task created on line 9 is returned. Notice that the operation’s return type is IAsyncResult. However, as stated in the beginning of this post, the Task class implements IAsyncResult interface. This is the key aspect to translate from the Task model into the APM model. The other aspect is the use of the state parameter when creating the task.

Regarding the End method:

  • On line 21, the IAsyncResult is casted to a task. Notice that, according to the APM, the IAsyncResult passed into the End method is the one returned by the Begin method.
  • Finally, the _exception and _response instance fields are consulted to produce an exception or response. These fields are assigned by the asynchronous process started on line 9 of the Begin method, as described in the following section.

Notice that the above code is rather generic. It could be used to implement other operations, just by changing line 9.

Using iterators to define asynchronous behavior

The typical way of defining asynchronous behavior with the Task<T> model is by chaining tasks with actions, producing other tasks. This breaks the code into multiple methods/anonymous methods/lambdas, reducing the readability.

In this post, we use an iterator based technique proposed by J. Richter for the APM and adapted to the Task<T> model by the ParallelExtensionExtras. The following code excerpt shows the asynchronous processing of the GetImageAndConvertItToJpeg method, implemented as a C# iterator.

 

private IEnumerable<Task> GetImageAndConvertItToJpeg(string uri)
{
    using (var client = new HttpClient
        {
            MaxResponseContentBufferSize = 1024*1024
        })
    {
        uri = Uri.UnescapeDataString(uri);
        Task<HttpResponseMessage> readTask = null;
        try
        {
            readTask = client.GetAsync(uri);
        }
        catch (Exception)
        {
            _exception = new HttpResponseException(HttpStatusCode.NotFound);
            yield break;
        }
        Trace("yielding for HTTP response...");
        yield return readTask;

        Trace("...resuming after HTTP response completed");
        if (readTask.IsFaulted || readTask.Result.StatusCode != HttpStatusCode.OK)
        {
            _exception = new HttpResponseException(HttpStatusCode.NotFound);
            yield break;
        }
        var httpContent = readTask.Result.Content;
        using (var ms = new MemoryStream())
        {
            var copyTask = httpContent.ContentReadStream.CopyStreamToStreamAsync(ms);
            Trace("yielding for stream copy...");
            yield return copyTask;

            Trace("...resuming after copy completed");
            if (copyTask.IsFaulted)
            {
                _exception = new HttpResponseException(HttpStatusCode.NotFound);
                yield break;
            }
            Bitmap bitmap = null;
            try
            {
                bitmap = new Bitmap(ms);
            }
            catch (Exception)
            {
                _exception = new HttpResponseException(HttpStatusCode.NotFound);
                yield break;
            }
            var output = new MemoryStream();
            bitmap.Save(output, ImageFormat.Jpeg);
            output.Seek(0, SeekOrigin.Begin);
            var content = new StreamContent(output);
            content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
            _response = new HttpResponseMessage
                {
                    Content = content
                };
        }
    }
}

 

This code performs the following:

  • An HttpClient is created to retrieve the upstream image. If any exception occurs while creating and starting the request, then the _exception instance field is assigned with an HttpResponseException and the iterator stops (yield break). If not, the result of the client.GetAsync(uri) statement is a Task<HttpResponseMessage>, representing the HTTP request. This task is then returned by the iterator, without blocking the hosting thread.
  • The iterator is resumed only when this Task<HttpResponseMessage> completes. Then it checks for errors, and if everything is ok, creates a task to copy the HttpResponseMessage’s stream into a memory stream. This is done to ensure that all the image’s content are in memory when the bitmap is created. If the bitmap was created directly from the  HttpResponseMessage’s stream, then the Bitmapconstructor would block the hosting thread while waiting for all the bytes (and we don’t want to block threads!).The stream copy uses the CopyStreamToStreamAsync extension method, also available on the ParallelExtensionExtras. The task returned by this method is then returned by the iterator, so that the stream copy is performed asynchronously.
  • The iterator is resumed again when the stream copy completes. After some error checking, the Bitmap is finally created and saved into another memory stream used in the response message. Notice that this can be done synchronously, since it doesn’t require any I/O.

Unfortunately, the above code is slightly cluttered by the error handling and by the fact that a yield statement cannot be inside a try-catch block.

The chaining of the tasks returned by the above iterator is done by the ParallelExtensionExtras Iterate method, that wraps the overall resulting asynchronous processing in a Task (remember line 9 of the second code excerpt).

This chaining is performed by the following:

  • When initially called, the Iterate method schedules a task, using StartNew, that will call the iterator to retrieve the first task. It also creates a TaskCompletionSource to represent the  overall task.
  • The first task retrieved from the iterator (representing the HTTP request) is then chained with another call to the iterator, using a ContinueWith.
  • The second task retrieved from the iterator (representing the stream copy) is also chained with another call to the iterator.
  • The final call to the iterator doesn’t return any element (MoveNext returns false), so Iterate signals the TaskCompletionSource that all the work is completed. This results in the call of the WCF callback.

The following diagram presents a sequence diagram, with the interaction between the different components.

async

The following color scheme is used:

  • Red – WCF runtime components;
  • Green – user code (Iterator represents the enumerable returned by the GetImageAndConvertItToJpeg method);
  • Light blue – TPL scheduler;
  • Dark blue – Iterate extension method (from the ParallelExtensionExtras)

The tracing output one of execution is (the first number is the managed thread id)

3: BeginGet…

6: yielding for HTTP response…

9: …resuming after HTTP response completed

9: yielding for stream copy…

6: …resuming after copy completed

6: Main task completed, calling callback

8: …EndGet

Conclusions and final remarks

  • Currently, WCF Web API only allows asynchronous operation implementations exposing the APM model.
  • However, it is not difficult to use a Task<T> based model with an APM interface, using the fact that Task implements IAsyncResult.
  • While the future C# 5 asynchronous support is not available, the use of iterators and the ParallelExtensionExtras’s Iterate method provides for a similar experience.
  • In this post I was not concerned with measuring the scalability improvements due to the use of asynchronous operation implementation. Namely, asynchronous processing may be disadvantageous if the blocking time is very small. My main goal here was the how and not the why of using asynchronous processing.
  • The ParallelExtensionExtras library is full of interesting utilities, of which the Iterate and the CopyStreamToStreamAsync are just examples.

Finally, feedback is greatly welcomed.

3 thoughts on “WCF Web API– Handling requests asynchronously

  1. Pingback: Distributed Weekly 115 — Scott Banwart's Blog

  2. Andrew

    Hi Pedro, I know this API has been deprecated but it was so useful and friendly…that we still use it we haven’t migrated to web api

    Anyways, I need your help, not sure if you are available.

    Basically for debugging purposes I need to be able to capture the request sent by our users.
    Everytime i google it, your blog shows up first.
    So, sorry if I bother you but do you know how to capture the request sent by users in v4 and in v6?

    So far I am able to get the headers and credentials but not the body for v6

    private void LogRequest(HttpRequestMessage request)
    {

    StringBuilder sb = new StringBuilder();
    if (request.Headers != null)
    sb.Append(“Headers: ” + request.Headers + “”);
    if (request.Headers.Authorization != null)
    {
    var credentials = ExtractCredentials(request.Headers.Authorization);
    sb.Append(“Credentials: ” + credentials.Username + “:” + credentials.Password + “”);
    }
    if (request.Method != null)
    sb.Append(“Method: ” + request.Method.ToString() + “”);
    if (request.RequestUri != null)
    sb.Append(“Request URI: ” + request.RequestUri.ToString() + “”);

    sb.Append(“IP Address: ” + Functions.GetIPAddress() + “”);

    //send email with this info

    }

    If i try with request.Content.ReadAsStringAsync() all I get is: System.Threading.Tasks.Task`1[System.String]

    for v4 i use the operationcontext

    private void LogRequest(OperationContext operationContext, APIUserCredentials credentials)
    {
    try
    {
    var request = operationContext.RequestContext.RequestMessage;
    StringBuilder sb = new StringBuilder();

    if (credentials != null)
    {

    sb.Append(“Credentials: ” + credentials.APIKey + ” : ” + credentials.Username +” : ” + credentials.Password + “”);
    }
    if (request.Headers.To.AbsoluteUri != null)
    sb.Append(“Method: ” + request.Headers.To.AbsoluteUri + “”);

    sb.Append(“IP Address: ” + Functions.GetIPAddress() + “”);

    //send email
    }
    catch (Exception ex)
    {
    ;
    }
    }

    your help will be appreciated

    Reply
    1. pedrofelix Post author

      Right, the ReadAsStringAsync method is asynchronous, so it returns a Task in this case. You should synchronize with this task completion to retrieve the string (e.g. via ContinueWith)

      Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s