HttpClient, Parsing Content, Awaiting and Showering :-)

Background

I’m making a short video with my colleague Andy about the HttpClient class that got introduced in .NET Framework 4.5 (the Windows 8 .NET Framework version) and specifically around how it’s packaged as a portable class library so that you can use it to build .NET code that’s portable ( at the binary level ) across Windows 8, Windows Phone and so on.

As an aside, there’s a new HTTP API introduced in Windows 8.1 that also surfaces as HttpClient and there’s a BUILD video that talks about that – it’s a WinRT thing rather than a portable .NET thing though and comes with new capabilities.

As part of talking about the HttpClient API, I wanted to show a little bit of code that did an HTTP request, got some data from a web service and parsed it into .NET objects. As I often do, I made use of the RESTful API up at flickR because it’s a very easy way of doing something that’s non-visual (i.e. and HTTP request) and turning it into something that is visual (i.e. a bunch of pictures) pretty quickly.

This is a pretty common thing to want to do – hit an HTTP API and get some JSON or XML back and turn it into some set of strongly typed .NET objects. Perhaps common enough to turn into some kind of library routine.

For example, I might try and write something like this;

  public static class HttpDownloader
  {
    public static async Task<List<RESULT>> DownloadAsync<RESULT,NODETYPE>(
      Uri downloadUri,
      Func<XElement, IEnumerable<NODETYPE>> selector,
      Func<NODETYPE, RESULT> projector) where NODETYPE : XNode
    {
      List<RESULT> resultsList = null;
      HttpClient client = new HttpClient();

      using (HttpResponseMessage response = await client.GetAsync(downloadUri))
      {
        if (response.IsSuccessStatusCode)
        {
          using (Stream stream = await response.Content.ReadAsStreamAsync())
          {
            XElement xml = XElement.Load(stream);

            // Try and get the selected elements...
            IEnumerable<NODETYPE> selectedElements = selector(xml);

            if (selectedElements != null)
            {
              // Try and get the projected data
              resultsList = selectedElements.Select(projector).ToList();
            }
          }
        }
      }
      return (resultsList);
    }
  }

I’m not sure this is really factored correctly because me hiding the use of HttpClient inside of this method makes it difficult to test and (e.g.) it makes it impossible for a caller to add a custom header or something similar to the request/response. However, hopefully the idea is clear – we’ll do an async GET to a particular URI and then we’ll parse the response as XML and then call some supplied function to select elements from that XML and then call some other supplied function to turn each of those XML elements into objects that end up on a list.

If I’m using this to call the flickR API which searches for photos I might have some .NET class to represent the sort of data that flickR returns as below and I’ve given that class a relatively simple constructor so that it can be instantiated from a piece of XML;

public class FlickrPhotoResult
{
  public FlickrPhotoResult(XElement photo)
  {
    Id = (long)photo.Attribute("id");
    Secret = photo.Attribute("secret").Value;
    Farm = (int)photo.Attribute("farm");
    Server = (int)photo.Attribute("server");
    Title = photo.Attribute("title").Value;
  }
  public long Id { get; private set; }
  public string Secret { get; private set; }
  public int Farm { get; private set; }
  public string Title { get; private set; }
  public int Server { get; private set; }

  public string ImageUrl
  {
    get
    {
      return (string.Format(
        "http://farm{0}.static.flickr.com/{1}/{2}_{3}_m.jpg",
        Farm, Server, Id, Secret));
    }
  }
}

Then I’m likely to have a viewmodel of some sort which (without listing all of the detail) might look something like the class below to support the idea that there is some SearchTerm that is to be searched for and some ICommand which causes the search to be executed and then some SearchResults collection which we populate with the results of the search;

 public class ViewModel : ViewModelBase
  {
    public ViewModel()
    {
      this.SearchFlickrCommand = new SimpleCommand(OnSearchFlickr);
    }
    public string SearchText
    {
      get
      {
        return (this._searchText);
      }
      set
      {
        base.SetProperty(ref this._searchText, value);
      }
    }
    public ICommand SearchFlickrCommand
    {
      get
      {
        return (this._searchFlickrCommand);
      }
      set
      {
        base.SetProperty(ref this._searchFlickrCommand, value);
      }
    }
    public List<FlickrPhotoResult> PhotoResults
    {
      get
      {
        return (this._photoResults);
      }
      set
      {
        base.SetProperty(ref this._photoResults, value);
      }
    }
    async void OnSearchFlickr()
    {
      if (!string.IsNullOrEmpty(this._searchText))
      {
        // Helper class to construct a URL that flickR's API understands
        FlickrSearchUrl flickrUrl = new FlickrSearchUrl(this.SearchText);

        IEnumerable<FlickrPhotoResult> results =
          await HttpDownloader.DownloadAsync<FlickrPhotoResult, XElement>(
            new Uri(flickrUrl.ToString()),
            xml => xml.DescendantsAndSelf("photo"),
            element => new FlickrPhotoResult(element));

        this.PhotoResults = results.ToList();
      }
    }
    List<FlickrPhotoResult> _photoResults;
    ICommand _searchFlickrCommand;
    string _searchText;
  }

where ViewModelBase implements INotifyPropertyChanged and SimpleCommand is a simple implementation of ICommand and I might then bind these things onto the screen to do something in the UI.

In the Shower…

I’ve had that code ( or something a lot like it ) kicking around for quite a while but the other day I was thinking about this in the shower and it came to me that it wasn’t particularly great.

I don’t know whether it’s common to dredge up some bit of code from the back of your mind while in the shower but I’ve found that it happens to me quite often and even though I hadn’t looked at this code for a while it suddenly hit me in the shower that it could be improved.

The real problem that occurred to me was that there’s not really a “Load XML Async” API which means that while my DownloadAsync<>() API might be asynchronous with respect to crossing the network, it’s not asynchronous with respect to the loading and parsing of XML.

This is a problem that needs to be fixed. Maybe…

The “Problem” Perhaps Isn’t a Problem

In terms of trying to better describe the “problem” that I thought I’d dreamt up in the shower, I can perhaps debug the code as in the screenshots below where I have a breakpoint on the line of code which is about to do the async HTTP GET for me;

image

and so this shows that the library function DownloadAsync<>() here is executed on thread 676 which is my UI thread. If I set another breakpoint, I can see that the continuation of this function;

image

is also executed on the same 676 thread (the UI thread) and there is then another piece of asynchronous work ( the function ReadAsStreamAsync() ) is kicked off and then there’s another continuation;

image

and then the parsing and loading of the XML is also done on that same thread 676.

So, there’s quite a lot of work here that’s all happening on the UI thread and, specifically, the work of loading the XML then finding the “photo” elements in the XML and transforming that XML data into a list of strongly typed .NET objects is all happening on the UI thread before, ultimately, this method “returns” back to the calling method which is in my view model class.

That method will then grab the results and put them into a property to be bound to the screen as below;

    async void OnSearchFlickr()
    {
      if (!string.IsNullOrEmpty(this._searchText))
      {
        // Helper class to construct a URL that flickR's API understands
        FlickrSearchUrl flickrUrl = new FlickrSearchUrl(this.SearchText);

        IEnumerable<FlickrPhotoResult> results =
          await HttpDownloader.DownloadAsync<FlickrPhotoResult, XElement>(
            new Uri(flickrUrl.ToString()),
            xml => xml.DescendantsAndSelf("photo"),
            element => new FlickrPhotoResult(element));

        this.PhotoResults = results.ToList();
      }
    }

Now, following my own thread that I wrote about await  it feels like I’m doing more work on the UI thread here than I need to or, more generally, more work in the caller’s synchronization context than I need to.

The only code that I really need to have execute on the UI thread is the viewmodel code which kicks off the async download and the viewmodel code that puts the results into a property to be data-bound by the UI.

Specifically, that assignment on line 14 of the code snippet above will cause a change notification event to be fired which data-binding will pick up and if that notification is not fired on the UI thread then the framework will complain by throwing an exception. The rest of the code which does work like parsing XML can (in this example) happen off the UI thread.

The real “problem” here is that my library function DownloadAsync<>() took the default route in its approach to using await. It assumed that it should capture the synchronization context of the caller and should assume responsibility for restoring it.

In this particular case, I don’t think that it needed to assume that responsibility. I think that library routine can leave that responsibility to the caller of the routine rather than making assumptions about what the caller wants.

As an aside, Stephen Cleary has a section on this topic in his MSDN Magazine article from March of this year.

That is – I can perhaps configure await to work differently by using ConfigureAwait(false);

   public static async Task<List<RESULT>> DownloadAsync<RESULT,NODETYPE>(
      Uri downloadUri,
      Func<XElement, IEnumerable<NODETYPE>> selector,
      Func<NODETYPE, RESULT> projector) where NODETYPE : XNode
    {
      List<RESULT> resultsList = null;
      HttpClient client = new HttpClient();

      using (HttpResponseMessage response = 
        await client.GetAsync(downloadUri).ConfigureAwait(false))
      {
        if (response.IsSuccessStatusCode)
        {
          using (Stream stream = await response.Content.ReadAsStreamAsync())
          {
            XElement xml = XElement.Load(stream);

            // Try and get the selected elements...
            IEnumerable<NODETYPE> selectedElements = selector(xml);

            if (selectedElements != null)
            {
              // Try and get the projected data
              resultsList = selectedElements.Select(projector).ToList();
            }
          }
        }
      }
      return (resultsList);
    }
  }

Line 10 is the only change above but that call to ConfigureAwait(false) is the difference between attempting to capture (and return) to the caller’s synchronization context and not attempting to do it.

That means that the pieces of work that are done as continuations here which are;

  • Line 12 where we continue after the async HTTP GET
  • Line 16 where we continue after the async reading of the HTTP response as a stream

are no longer done on the UI thread which means that the loading, parsing, manipulating of the XML data is not done on the UI thread which you have to assume is a good thing from the point of view of keeping the UI thread as free of “additional” work as possible and thereby keeping the UI responsive. Instead, that work will be done on whatever threadpool thread has been dispatched to complete the async IO work that is begun on line 10 and then line 14 above.

I’m pretty sure I’ve written something like this blog-post before around a similar topic but I thought I’d flag it up again because, for me, that very simple looking true/false value passed to ConfigureAwait() hidden down in my library routine seems like a very easy and small thing to miss and yet it has huge implications for how the code actually functions at run time.

As always, feel free to flag mistakes – I make a lot of them Smile