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