Caliburn Meets TPL / Async
With C# and Async integration in the language, you’ll wonder how this fits in your current application infrastructure. I have started porting an old application into Silverlight 5.0 which comes with new C# 5.0 and Async features and I needed a way to integrate this with the Calibrun framework I had in place.
Caliburn Async Abstractions
In Caliburn you could expose your ViewModel actions as IResult / IEnumerable<IResult>
. I have blogged about this before, but in short, it is a good way to abstract away the whole async stuff you have in your ViewModel and it made testing async actions in the view model much easier. Here’s a typical action I had on a ViewModel:
1 | public IEnumerable<IResult> LoadEmployee() |
By using IResult we have modified the whole async and continuation into coroutines which is much cleaner to read and easier to follow.
Hello Async
Now with async stuff in the horizon, how would async / await fit this scenario? Let’s suppose we have the following async method in our View Model:
1 | private void LoadEmployeeAsync() |
At first we should convert this service call into the new async pattern:
1 | private async Task<Employee> LoadEmployeeAsync() |
A couple of things to notice: We are now using the interface of the generated service, which exposes IAsyncResult and we’re returning the method call with a Task<TResult>
. With the new async pattern, your method should either return void or Task / Task<T>
before you can use the async keyword.
There’s an IResult for that
Now the question is how to call the async method in a sequence of IResults. This would be the first attempt:
1 | public IEnumerable<IResult> LoadEmployee() |
Apparently this won’t work as expected because as soon as we call the async method it will return and we’ll fire the Completed event on IResult which will move to execution of the next IResult in the sequence. What we want to do is to wait for the completion of the Task and then raise the Completed event, so I came up with this implementation:
1 | public class TaskResult : IResult |
This is just the same API that is available today on TPL, so nothing fancy, the only thing worth mentioning here is that we’re raising the Completed event on the UI thread using Execute class of Caliburn. The Execute class uses IDispatcher interface that wraps Silverlight / WPF dispatcher object. The final version of the TaskResult can be used like this:
1 | public IEnumerable<IResult> LoadEmployee() |
This now fully supports calling Task
or Task<T>
methods and also has its own continuation support. This works right alongside other IResult implementations. Ideas?