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:
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:
async/await
is out of the question. However, if it would work with async/await
feel free to show how.An asynchronous task is defined by a computation that runs on a background thread and whose result is published on the UI thread. An asynchronous task is defined by 3 generic types, called Params , Progress and Result , and 4 steps, called onPreExecute , doInBackground , onProgressUpdate and onPostExecute .
What Is A Task In C#? A task in C# is used to implement Task-based Asynchronous Programming and was introduced with the . NET Framework 4. The Task object is typically executed asynchronously on a thread pool thread rather than synchronously on the main thread of the application.
For more information, I have an async / await intro on my blog. So additionally, if a method with multiple awaits is called by a caller, the responsibility for finishing every statement of that method is with the caller.
C# has a language-level asynchronous programming model, which allows for easily writing asynchronous code without having to juggle callbacks or conform to a library that supports asynchrony. It follows what is known as the Task-based Asynchronous Pattern (TAP).
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. :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With