CodeProject 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;
}