Tuesday, January 31, 2012

SimpleDataListSource – Consuming Data From Simple Services

In my last post I introduced the data framework exposed as part of the Cocoon framework project. Whilst the same principles could be applied to any presentation layer, this framework is designed from the ground up to work great with Windows 8 Metro applications written in managed .Net languages. This includes support for several of the advanced features of WinRT based UIs, such as data virtualization (which I discussed in this post).

As I discussed, Cocoon splits the passing of data from a data source into the UI with two parts. The DataListSource (represented by the IDataListSource<T> interface) describes how the data is retrieved and maps well onto the typical web service API calls to do so. At the other end of the pipeline is the DataList whose responsibility it is to determine when to retrieve the data and to present it in a format that is easily bound to the UI.

Whilst this system is designed to be easily extensible, there are a number of typical use-cases that are provided out of the box with the Cocoon framework. In this post I will describe the SimpleDataListSource.

The SimpleDataListSource Class

The SimpleDataListSource<T>, as its name suggests, is an implementation of the IDataListSource<T> interface for use with simple web APIs that return all items in a list with a single API call.

As an example consider the Flickr API method flickr.photos.people.getList that returns all the people that are tagged in a given photo. Since the number of people is likely to be relatively small the API simply takes a photo ID and returns all the people in one go, and is an ideal candidate for the SimpleDataListSource<T>. This is in contrast to a method such as flickr.interestingness.getList that returns all the interesting photos for the current day. In this case they may be many hundred items so the Flickr API splits these into several pages that are returned one at a time.

In code form we could consider this as,

public class FlickrApi
{
    public Task<IList<PeopleTag>> GetPeopleInPhoto(string photoId)
    {
        ...
    }
 
    public Task<IList<Photo>> GetInterestingPhotos(int page)
    {
        ...
    }
}

Implementing A Simple Data Source

Since SimpleDataSource<T> is an abstract class you must first derive a custom class for a specific data type. The only method you then are required to implement is the FetchItemsAsync() method that will initiate the call to the web API to retrieve all the items.

For our Flickr photo tagging example,

public class TaggedPeopleDataListSource : SimpleDataSource<PeopleTag>
{
    // *** Fields ***
 
    private FlickrApi flickrApi;
    private string photoId;
 
    // *** Constructors ***
 
    public TaggedPeopleDataListSource(string photoId, FlickrApi flickrApi)
    {
        this.flickrApi = flickrApi;
        this.photoId = photoId;
    }
 
    // *** Overriden Methods ***
 
    protected override Task<IList<PeopleTag>> FetchItemsAsync()
    {
        return flickrApi.GetPeopleInPhoto(string photoId);
    }
}

Here we firstly derive from ‘SimpleDataListSource<PeopleTag>’ (since every item in the list is of type ‘PeopleTag’). In the constructor we take the photo ID to retrieve the tagged people, and a reference to the ‘FlickrApi’ implementation. In the FetchItemsAsync() method we simply call the API method and return the result.

The underlying SimpleDataListSource<T> implementation will ensure that the web API is only called once, and will cache the results in memory for future use.

As usual the code is freely available for download from the Cocoon CodePlex site (to get the latest version go to the “Source Code” tab, select the first change set and use the “Download” link).

Next Time

Whilst simple scenarios such as those supported by the SimpleDataListSource are relatively basic to implement without the support provided by the Cocoon framework, many web APIs return paged results that are much more difficult to consume. For a fast and responsive UI these should be retrieved asynchronously and on demand as the user scrolls through a long list of items.

Next time I will introduce the PagedDataListSource that allows you to support this with minimal code. After that I will introduce the final piece in the puzzle – the DataList that can be connected to any of these DataListSources for binding to the UI. Finally I will describe a simple end-to-end example of how to use the data framework to bind to a real web service.

4 comments:

GMan said...

Hi Andy,

Could I ask that you include another Page which demonstrates the Flickr API using the SimpleDataListSource in your Cocoon.Samples project?

You currently only demo the PagedDataListSource, thanks and I just want to double check my logic!

GMan said...

Ok that was actually pretty easy (Sorry to spam your blog again)

It seems to be as easy as:

protected override Task> FetchItemsAsync()
{
return flickrApi.GetInterestingPhotos(1, 20);
}

:)

Unknown said...

GMan,

Yes - That would be the way to use SimpleDataListSource to retrieve Flickr interesting phots (although of course this will only show a static list of the first 20 items).

SimpleDataListSource is designed for cases where a small number of items are to be retrieved in a single call. Continuing the Flickr example, you might use SimpleDataListSource when retrieving all of a user's photo sets (i.e. albums) - there are likely to be only a small number of these that are retrieved with a single API call.

In contrast you would probably use PagedDataListSource for Flickr interesting photos as there are a large number of these and returned in a paged manner (of course you could use something like 'flickrApi.GetInterestingPhotos(1,500)' although this might take a while!).

GMan said...

Ok thanks Andy.

I did leave you another post regarding your sample but feel free to not bother about that unless you have the time. I have bombarded you enough :)

Take care.