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?

Original source