Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

OData with async

4.67/5 (2 votes)
10 Sep 2012CPOL 13.2K  
Using 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

C#
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 creates an OData service reference, runs a database query against it, and shows the results.

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

There seems 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:

C#
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:

C#
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!

C#
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;
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)