Sequential processing of asynchronous tasks
.net, .net-4.0, c#, task-parallel-library
Solution
Here's how it would work with `async`:
try
{
await FooAsync();
await BarAsync();
await FubarAsync();
Console.WriteLine("All done");
}
catch(Exception e) // For illustration purposes only. Catch specific exceptions!
{
Console.WriteLine(e);
}
This would work on .NET 4.0 if you installed the (prerelease) Microsoft.Bcl.Async package.
Since you're stuck on VS2010, you can use a variant of Stephen Toub's `Then`:
public static Task Then(this Task first, Func<Task> next)
{
var tcs = new TaskCompletionSource<object>();
first.ContinueWith(_ =>
{
if (first.IsFaulted) tcs.TrySetException(first.Exception.InnerExceptions);
else if (first.IsCanceled) tcs.TrySetCanceled();
else
{
try
{
next().ContinueWith(t =>
{
if (t.IsFaulted) tcs.TrySetException(t.Exception.InnerExceptions);
else if (t.IsCanceled) tcs.TrySetCanceled();
else tcs.TrySetResult(null);
}, TaskContinuationOptions.ExecuteSynchronously);
}
catch (Exception exc) { tcs.TrySetException(exc); }
}
}, TaskContinuationOptions.ExecuteSynchronously);
return tcs.Task;
}
You can use it as such:
var task = FooAsync().Then(() => BarAsync()).Then(() => FubarAsync());
task.ContinueWith(t =>
{
if (t.IsFaulted || t.IsCanceled)
{
var e = t.Exception.InnerException;
// exception handling
}
else
{
Console.WriteLine("All done");
}
}, TaskContinuationOptions.ExcecuteSynchronously);
Using Rx, it would look like this (assuming you don't have the `async` methods already exposed as `IObservable<Unit>`):
FooAsync().ToObservable()
.SelectMany(_ => BarAsync().ToObservable())
.SelectMany(_ => FubarAsync().ToObservable())
.Subscribe(_ => { Console.WriteLine("All done"); },
e => { Console.WriteLine(e); });
I think. I'm not an Rx master, by any means. :)
Problem
Assume the following synchronous code: ``` try { Foo(); Bar(); Fubar(); Console.WriteLine("All done"); } catch(Exception e) // For illustration purposes only. Catch specific exceptions! { Console.WriteLine(e); } ``` Now assume all these methods have an Async counterpart and I have to use those for some reason, so simply wrapping the whole thing in a new task is not an option. How would I achieve the same behavior? What I mean with "same" is: - Execute a handler for the exception, if one is thrown. - Stop execution of the following methods, if an exception is thrown. The only thing I was able to come up with is horrible: ``` var fooTask = FooAsync(); fooTask.ContinueWith(t => HandleError(t.Exception), TaskContinuationOptions.OnlyOnFaulted); fooTask.ContinueWith( t => { var barTask = BarAsync(); barTask.ContinueWith(t => HandleError(t.Exception), TaskContinuationOptions.OnlyOnFaulted); barTask.ContinueWith( t => { var fubarTask = FubarAsync(); fubarTask.ContinueWith(t => HandleError(t.Exception), TaskContinuationOptions.OnlyOnFaulted); fubarTask.ContinueWith( t => Console.WriteLine("All done"), TaskContinuationOptions.OnlyOnRanToCompletion); }, TaskContinuationOptions.OnlyOnRanToCompletion); }, TaskContinuationOptions.OnlyOnRanToCompletion); ``` Please note: - I need a solution that works with .NET 4, so `async/await` is out of the question. However, if it would work with `async/await` feel free to show how. - I don't need to use the TPL. If it is impossible with the TPL another approach would be OK, maybe with Reactive Extensions?