Extending the OData Async Extensions to DataServiceCollection Methods

UPDATED 8/5/2013: Turns out that I didn't have my DataServiceCollection<T> methods defined correctly as extension methods (forgot the this keyword on the bindingCollection parameter).

As I announced in a previous post, there is an OData client library that supports Windows Store app development. This is a the good news, but folks who have tried to use it in their Windows Store apps are quick to note that the library’s asynchronous APIs don’t support the nice new await/async behaviors in .NET Framework 4.5. Our friend Phani Raju provided a bit of help here in his post Async extension methods for OData Windows 8 client library. In this post, Phani provides us with some nice awaitable wrappers around the Begin/End methods in the OData client APIs. This makes is easy to add these extension methods into your project and use the await pattern, like this:

         var results = await ODataAsyncExtensions
            .ExecuteAsync<AnswerLink>(_context.AnswerLinks);

I used var to define the variable…but when you code this, you will notice that this awaitable method (along with the other Execute and Load methods) actually returns an IEnumerable<T>, which is not the ideal collection for data binding, especially two-way binding. OData clients already have an ideal binding collection in DataServiceCollection<T>, but Phani didn’t provide for us the nice awaitable wrapper for the load methods on this collection.

Fortunately, I came across the article  Convert Events to Async methods posted by Mandelbug, which showed how to convert the old style event/delegate based async operation into an awaitable Task-based one. As such, an awaitable version of the LoadAsync(DataServiceQuery) method looks like this:

         public static async Task<LoadCompletedEventArgs> 
            LoadAsync<T>(this DataServiceCollection<T> bindingCollection, 
            DataServiceQuery<T> query)
        {            
            var tcs = new TaskCompletionSource<LoadCompletedEventArgs>();

            EventHandler<LoadCompletedEventArgs> handler = 
                delegate(object o, LoadCompletedEventArgs e)
            {
                if (e.Error != null)
                {
                    tcs.TrySetException(e.Error);
                }
                else if (e.Cancelled)
                {
                    tcs.TrySetCanceled();
                }
                else
                {
                    tcs.TrySetResult(e);
                }
            };

            bindingCollection.LoadCompleted += handler;
            bindingCollection.LoadAsync(query);

            LoadCompletedEventArgs eventArgs = await tcs.Task;
            bindingCollection.LoadCompleted -= handler;

            return eventArgs;
        }

I have attached the entire ODataAsyncExtensions class code page to this post, which includes Phani’s methods plus my new LoadAsync ones. As always, this code is provided to you “as is," I ‘m not going to support it, so use it at your own risk….but please let me know if you find any bugs.

 

Cheers,

Glenn Gailey

ODataAsyncExtensions.cs