Lloyd.NET

Programing experiments

OData with async

Today I watched this video about using OData in a WinRT app:
http://blog.jerrynixon.com/2012/08/new-episode-devradio-let-odata-make.html

To summarize he (Jerry Nixon) add a service reference to the Netflix OData API at:
http://odata.netflix.com/Catalog/

 

and then proceed to do something like that

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    var _uri = new Uri("http://odata.netflix.com/Catalog/");
    var ctxt = new NetFlixService.NetflixCatalog(_uri);
    var data = new DataServiceCollection<NetFlixService.Title>(ctxt);

    var query = from t in ctxt.Titles
                where t.Name.Contains("Star Trek")
                select t;
    data.LoadCompleted += delegate 
    {
        this.DataContext = data;
    };
    data.LoadAsync(query);
}

Basically he create an OData service reference, run a database query against it and show the results.

 

What I wanted to change is, use the new async / await keyword in .NET4.5 instead of the LoadCompleted delegate.

There seem to be no obvious way of doing that!
Time to Google!

From the await (C# Reference) reference it seems that await can (only) be applied to a method returning a Task, and a Task (from Googling) can be created from IAsyncResult.

 

So first I started by creating a very simple and reusable IAsyncResult implementation class:

public class SimpleAsyncResult : IAsyncResult, IDisposable
{
    ManualResetEvent waitHandle = new ManualResetEvent(false);

    public void Finish()
    {
        IsCompleted = true;
        waitHandle.Set();
        waitHandle.Dispose();
    }

    public void Dispose() { waitHandle.Dispose(); }

    public bool IsCompleted { get; private set; }
    public object AsyncState { get; set; }
    public bool CompletedSynchronously { get; set; }

    public WaitHandle AsyncWaitHandle { get { return waitHandle; } }
}

 

With that I can easily create an extension method for my OData classes returning a Task:

public static class OData
{
    public static Task<DataServiceCollection<T>> AsyncQuery<T>(this DataServiceCollection<T> data, IQueryable<T> query = null)
    {
        var asyncr = new SimpleAsyncResult();
        Exception exResult = null;
        data.LoadCompleted += delegate(object sender, LoadCompletedEventArgs e)
        {
            exResult = e.Error;
            asyncr.Finish();
        };

        if (query == null)
            data.LoadAsync();
        else
            data.LoadAsync(query);

        return Task<DataServiceCollection<T>>.Factory.FromAsync(asyncr
            , r =>
            {
                if (exResult != null)
                    throw new AggregateException("Async call problem", exResult);
                return data;
            }
        );
    }
}

Remark here I wrap the exception because I don’t want to lose the stack trace (with “throw exResult”)

 

And voila I can update my NavigatedTo method to be async friendly!

protected async override void OnNavigatedTo(NavigationEventArgs e)
{
    var _uri = new Uri("http://odata.netflix.com/Catalog/");
    var ctxt = new NetFlixService.NetflixCatalog(_uri);
    var data = new DataServiceCollection<NetFlixService.Title>(ctxt);

    var query = from t in ctxt.Titles
                where t.Name.Contains("Star Trek")
                select t;
    await data.AsyncQuery(query);
    this.DataContext = data;
}

Tags:
Categories: .NET
Permalink | Comments (0) | Post RSSRSS comment feed
blog comments powered by Disqus