Introduction
In this short tip, I explain how I made an OData
sample using the async extension of .NET 4.5.
Using the Code
Today, I watched this video about using OData
in a WinRT app.
To summarize, he (Jerry Nixon) adds a service reference to the Netflix OData API at http://odata.netflix.com/ and then proceeds to do something like:
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 will show is how to improve this, how to use the new async
/ await
keywords 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 use the .NET4.5 async extension!
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;
}
Points of Interest
This is a nice way to explore some internals of the async
extension in .NET4.5.
History