Prevent Task.ContinueWith on exception - c#

I am trying to prevent a task from continuing if the first part fails.
My code looks like that:
Task listener = Task.Factory.StartNew(openConnection).ContinueWith((t) => listenForNumber());
void openConnection()
{
try
{
//stuff
}
catch
{
//morestuff
}
}
void listenForNumber()
{
//even more stuff
}
Now listenForNuber() should not be executed if openConnection() enters the catch block
I tried ContinueWith((t) => listenForNumber(),TaskContinuationOptions.NotOnFaulted);
But no success, any help? :(
Thanks

TaskContiuationOptions.NotOnFaulted will obviously have no effect unless your method has faulted, i.e. an exception thrown during its execution was unhandled.
In your catch block, you should re-throw the exception (and preserve the stack trace) using the throw; statement after you've performed your work (some clean-up maybe) - otherwise the exception won't be thrown again, so your method will not be considered as 'faulted'.

Create an extension method helper.
public static void PropagateExceptions(this Task task)
{
if (task == null)
throw new ArgumentNullException("task");
if (!task.IsCompleted)
throw new InvalidOperationException("The task has not completed yet.");
if (task.IsFaulted)
task.Wait();
}
then call PropagateExceptions() extension method before executing any codes. PropagateExceptions() method will also rethrow if the task was cancelled.
t1.ContinueWith(t => {
t.PropagateExceptions();
listenForNumber();
});

You need to throw the exception in your task method. The TPL does not know the method has failed, unless it catches an exception.
You will still need to have a continuation method for the faulted case. This could be a simple method that logs the exception.
If you don't have a continuation method for the exception, you will get unhandled exceptions in your application when your task method throws an exception.

Related

Not awaitable method exception thowing inconsistent behaviour

So I read on async/await and somewhere, someplace I read that if you don't await an async method you basically lose it. It fires and forgets and goes into the AEeher and if it throws an exception - you will never know.
This was the example the author used:
static async void OnButtonClick()
{
yolo();
string imageUrl = null;
try
{
DownloadAndBlur(imageUrl);
}
catch (Exception ex)
{
Console.WriteLine($"Exception: {ex}");
}
Console.WriteLine("Done!");
}
static async Task DownloadAndBlur(string url)
{
if (url == null)
{
throw new ArgumentNullException(nameof(url));
}
}
Indeed, if I call the OnButtonClick() method from my code no exception gets thrown, or rather, nothing about an exception is printed on the console. While if I await the DownloadAndBlur method - an exception is written to the console.
So I tried to replicate the behaviour and wrote this:
static async void Execute()
{
Console.WriteLine(1);
yolo();
Console.WriteLine(2);
}
static Task yolo()
{
throw new Exception();
}
But an exception is thrown and my debugging session catches it. So what is different, because I think they are the same.
The Execute method is not fire-and-forget. It is async void.
static async void Execute()
{
YoloAsync();
}
Exceptions in async void methods are thrown in the current SynchronizationContext (or in the ThreadPool if the SynchronizationContext.Current is null), which normally results to the crashing of the process (source code).
Next, the YoloAsync method is not marked with the async modifier.
static Task YoloAsync()
{
throw new Exception();
}
Semantically it is an asynchronous method since it returns a Task, but the task is not generated from an async-state-machine. So the code inside the YoloAsync method is executed synchronously like any other method, and unlike the async-state-machine-generated methods that propagate their exceptions through the Task they return.
Maxim 26. "Fire and Forget" is fine, provided you never actually forget.
Getting a Exception in Multitasking is always difficulty.
If you are doing Mutlthreading, it is actually trivially easy to loose all exceptions by default. The thread itself swallows all Exceptions. This is the worst case that has to be handeled.
As a result, Multitasking approaches always catch all exceptions, then expose them in the Result. Task has a property for that. So Does RunWorkerCompletedEventArgs.
One job of the continuation code, is to check for and re-raise any Exceptions. It is something Task has to do for Multithreading support, even if it does not nessearily make sense with mere Multitasking.

Task continue with not working upon exception

I am in a strange situation, I am using task and continue with upon faulted i am calling one method to process upon faulted or success but the function does not get fired.
Below is my code but upon expcetion it does not executes the UdpateResult method, what I am missing here.
var task = new Task.Factory.StartNew(SomeMethod());
task.ContinueWith(
t1 => Handler.UpdateResult(t1.Result, t1.Exception),
TaskContinuationOptions.ExecuteSynchronously);
try
{
task.Wait();
}
catch (AggregateException exception)
{
foreach (var innerException in exception.Flatten().InnerExceptions)
{
if (innerException is InvalidOperationException)
{
throw innerException;
}
throw new InvalidOperationException(string.Empty, innerException);
}
}
You're trying to use t1.Result within your continuation. If t1 has faulted, then accessing t1.Result will itself throw an exception.
You either need a single continuation which can handle any kind of end result, or you should attach different continuations for success and failure cases.

Problems with handling exceptions from async method with tasks

I hope you can help me with that problem.
I have a method that does specific actions, for example, I am sending a HttpWebRequest. There I can get a WebException, so I put it in a Try-Catch-block to rethrow exceptions for more specific exception messages.
Like that: (This is in a method called doWebRequest)
try
{
// HttpWebRequest here
}
catch (WebException ex)
{
throw new WebException(String.Format("My special additional message {0}", ex.Message);
}
Well, so this works, when I call this function normally.
But now I want an async way to do this. What I made to call this method in an async method:
public void DoRequestAsync()
{
Task internalRequest = new Task(doWebRequest);
internalRequest.ContinueWith(InternalUpdateSearchExceptionHandler, TaskContinuationOptions.OnlyOnFaulted);
internalRequest.Start();
}
So this makes a new task and then calls the method doWebRequest async.
To handle errors now, because I know it is different on async, I made this handler, which you can also see in internalRequest.ContinueWith. Looks like that:
private void InternalUpdateSearchExceptionHandler(Task task)
{
var ex = task.Exception;
if (ex.InnerException is WebException)
{
if ((ex.InnerException as WebException).Status == WebExceptionStatus.ProtocolError)
{
throw new WebException(ex.InnerException.Message);
}
else
{
throw new Exception("There was no response from the server.");
}
}
}
But this is not executing any exceptions. I don't know why.
At first I thought, this is because it cannot take the InnerException as a WebException, or would that work? If not, please tell me what to do here. But even when I throw an exception without any queries here, it did not throw any exceptions while debugging. Why is that?
Help is appreciated. When something is not clear, ask me. ;)
Your continuation is throwing an exception, but when that continuation throws an exception all that happens is the Task that represents that continuation is marked as Faulted with the given exception as its Exception. You currently are ignoring the task created by calling ContinueWith, so there is nothing to observe this exception.
DoRequestAsync likely shouldn't be void; rather it should return a Task, specifically the one created by calling ContinueWith, so that whoever calls this method can observe any exceptions thrown.
Also note that you could do this much more simply using async:
public async Task DoRequestAsync()
{
try
{
var content = await new WebClient()
.DownloadStringTaskAsync("address");
}
catch (WebException ex)
{
throw new WebException(String.Format("My special additional message {0}", ex.Message);
}
}

Contract agreement when implementing a method that returns a Task

Is there a MS "best practice" or contract agreement when implementing a method that returns a Task in regards to throwing exceptions? This came up when writing unit tests and I was trying to figure out if I should to test/handle this condition (I recognize that the answer could be "defensive coding", but I don't want that to be the answer).
i.e.
Method must always return a Task, which should contain the thrown Exception.
Method must always return a Task, except when the method supplies invalid arguments (i.e. ArgumentException).
Method must always return a Task, except when the developer goes rogue and does what he/she wants (jk).
Task Foo1Async(string id){
if(id == null){
throw new ArgumentNullException();
}
// do stuff
}
Task Foo2Async(string id){
if(id == null){
var source = new TaskCompletionSource<bool>();
source.SetException(new ArgumentNullException());
return source.Task;
}
// do stuff
}
Task Bar(string id){
// argument checking
if(id == null) throw new ArgumentNullException("id")
try{
return this.SomeService.GetAsync(id).ContinueWith(t => {
// checking for Fault state here
// pass exception through.
})
}catch(Exception ex){
// handling more Fault state here.
// defensive code.
// return Task with Exception.
var source = new TaskCompletionSource<bool>();
source.SetException(ex);
return source.Task;
}
}
I've asked a somewhat similar question recently:
Handling exceptions from the synchronous part of async method.
If the method has an async signature, it doesn't matter if you throw from the synchronous or asynchronous part of method. In both cases, the exception will be stored inside the Task. The only difference is that the resulting Task object will be instantly completed (faulted) in the former case.
If the method doesn't have async signature, the exception may be thrown on the caller's stack frame.
IMO, in either case the caller should not make any assumption about whether the exception has been thrown from the synchronous or asynchronous part, or whether the method has async signature, at all.
If you really need to know if the task has completed synchronously, you can always check its Task.Completed/Faulted/Cancelled status, or Task.Exception property, without awaiting:
try
{
var task = Foo1Async(id);
// check if completed synchronously with any error
// other than OperationCanceledException
if (task.IsFaulted)
{
// you have three options here:
// 1) Inspect task.Exception
// 2) re-throw with await, if the caller is an async method
await task;
// 3) re-throw by checking task.Result
// or calling task.Wait(), the latter works for both Task<T> and Task
}
}
catch (Exception e)
{
// handle exceptions from synchronous part of Foo1Async,
// if it doesn't have `async` signature
Debug.Print(e.ToString())
throw;
}
However, normally you should just await the result, without caring if the task has completed synchronously or asynchronously, and which part has possibly thrown. Any exception will be re-thrown on the caller context:
try
{
var result = await Foo1Async(id);
}
catch (Exception ex)
{
// handle it
Debug.Print(ex.ToString());
}
This works for unit testing too, as long as the async method returns a Task (the Unit Test engine doesn't support async void method, AFAIK, which makes sense: there is no Task to keep track of and await).
Back to your code, I'd put it this way:
Task Foo1Async(string id){
if(id == null) {
throw new ArgumentNullException();
}
// do stuff
}
Task Foo2Async(string id) {
if(id == null){
throw new ArgumentNullException();
}
// do stuff
}
Task Bar(string id) {
// argument checking
if(id == null) throw new ArgumentNullException("id")
return this.SomeService.GetAsync(id);
}
Let the caller of Foo1Async, Foo2Async, Bar deal with the exceptions, rather than capturing and propagating them manually.
I know that Jon Skeet is a fan of doing precondition-style checks in a separate synchronous method so that they are thrown directly.
However, my own opinion is "it doesn't matter". Consider Eric Lippert's exception taxonomy. We all agree that exogenous exceptions should be placed on the returned Task (not thrown directly on the caller's stack frame). Vexing exceptions should be completely avoided. The only types of exceptions in question are boneheaded exceptions (e.g., argument exceptions).
My argument is that it doesn't matter how they're thrown because you shouldn't write production code that catches them. Your unit tests are the only code that should be catching ArgumentException and friends, and if you use await then it doesn't matter when they're thrown.
The general case when methods return tasks is because they are asynchronous methods. In these cases it's common that an exception in the synchronous part of the method should be thrown just like in any other method, and in the asynchronous part should be stored inside the returned Task (automatically by calling an async method or anonymous delegate).
So, in the simple cases like invalid parameters simply throw an exception like in Foo1Async. In the more complex case regarding the asynchronous operation set an exception on the returned task like in Foo2Async
This answer assumes you're referring to Task returning methods that aren't marked with async. In those that are you have no control over the task being created, and any exception would automatically be stored in that task (so the question would be irrelevant).

Task<T> and TaskContinuationOptions Clarification in C#?

I have this simple code :
var g= Task.Factory.StartNew<int> (() => 8)
.ContinueWith (ant =>{throw null;})
.ContinueWith (a =>{ Console.WriteLine("OK");},TaskContinuationOptions.NotOnFaulted);
try{
Console.WriteLine("1");
g.Wait();
Console.WriteLine("2");
}
catch (AggregateException ex)
{Console.WriteLine("catch"); }
The Output :
1
catch
System.AggregateException: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread.
msdn :
TaskContinuationOptions.NotOnFaulted
Specifies that the continuation task should not be scheduled if its
antecedent threw an unhandled exception. This option is not valid for
multi-task continuations.
ok .
And it is ok - not showing this line cause the prev line DID throw exception.
Questions :
Do I get the AggregateException exception because I haven't inspected the Exception property ?
Must I always inspect if the antecedent throw an exception ( in each line ? ) ? ( I can't check each line ! it doesn't make any sense and very annoying)
Wasn't the try catch block should have swallow the exception ? ( I thought that all exceptions bubble up to the wait method....so ? )
Do I get the AggregateException exception because I haven't inspected
the Exception property ?
No, you get an exception, because task g cancels by TPL(because, as msdn stated, this task will not scheduled if antescendent task throws an exception).
We have 3 tasks here:
Original Task (that uses StartNew)
First Continuation Task (that throws an exception)
Second Continuation Task (that prints OK) (this is g task from your code).
The issue is that you ask TPL to start 3d task only if 2nd task will finished successfully. This means that if this condition will not met TPL will cancel your newly created task entirely.
You got unobserved task exception because you have temporary task (task 2 in my list) that you never observe. An because you never observe it faulted state it will throw in finalizer to tell you about it.
You can check this by printing task's status in catch block:
catch (AggregateException ex)
{
Console.WriteLine("catch");
// Will print: Status in catch: Canceled
Console.WriteLine("Status in catch: {0}", g.Status);
}
Must I always inspect if the antecedent throw an exception ( in each
line ? ) ? ( I can't check each line ! it doesn't make any sense and
very annoying)
Yes you should observe antecedent tasks exception to avoid this issue:
static class TaskEx
{
public static Task ObserverExceptions(this Task task)
{
task.ContinueWith(t => { var ignore = t.Exception; },
TaskContinuationOptions.OnlyOnFaulted);
return task;
}
}
And then use it as following:
var g= Task.Factory.StartNew<int> (() => 8)
.ContinueWith (ant =>{throw null;})
.ObserveExceptions()
.ContinueWith (a =>{ Console.WriteLine("OK");});
try{
Console.WriteLine("1");
g.Wait();
Console.WriteLine("2");
}
catch (AggregateException ex)
{Console.WriteLine("catch"); }
UPDATE: Added solution to last bullet
Wasn't the try catch block should have swallow the exception ? ( I
thought that all exceptions bubble up to the wait method....so ? )
We have set of extension method (called TransformWith) in our project that can solve this particular issue and gain following:
Exception would bubble up to the catch block and
We'll not crash application with TaskUnobservedException
Here the usage
var g = Task.Factory.StartNew(() => 8)
.ContinueWith(ant => { throw null; })
// Using our extension method instead of simple ContinueWith
.TransformWith(t => Console.WriteLine("OK"));
try
{
Console.WriteLine("1");
// Will fail with NullReferenceException (inside AggregateExcpetion)
g.Wait();
Console.WriteLine("2");
}
catch (AggregateException ex)
{
// ex.InnerException is a NullReferenceException
Console.WriteLine(ex.InnerException);
}
And here is a extension method:
static class TaskEx
{
public static Task TransformWith(this Task future, Action<Task> continuation)
{
var tcs = new TaskCompletionSource<object>();
future
.ContinueWith(t =>
{
if (t.IsCanceled)
{
tcs.SetCanceled();
}
else if (t.IsFaulted)
{
tcs.SetException(t.Exception.InnerExceptions);
}
else
{
try
{
continuation(future);
tcs.SetResult(null);
}
catch (Exception e)
{
tcs.SetException(e);
}
}
}, TaskContinuationOptions.ExecuteSynchronously);
return tcs.Task;
}
}
Do I get the AggregateException exception because I haven't inspected
the Exception property ?
Tasks always throw AggregateException : http://msdn.microsoft.com/en-us/library/system.threading.tasks.task.exception.aspx
You can get the original exception using :
var myTask = Task.Factory.StartNew(() => { throw new NotImplementedException(); });
var myException = myTask.Exception.Flatten().InnerException as NotImplementedException;
Must I always inspect if the antecedent throw an exception ( in each
line ? ) ? ( I can't check each line ! it doesn't make any sense and
very annoying)
Yes it is anoying, you should create two continuations for each task to check exceptions : one that checks if there has been an exception to handle it, and another one to continue the operation if there was no exception see TaskContinuationOptions.OnlyOnFaulted and TaskContinuationOptions.OnlyOnRanToCompletion.
You should even create a third continuation to deal with cancellation if needed.
Wasn't the try catch block should have swallow the exception ? ( I
thought that all exceptions bubble up to the wait method....so ? )
No it won't, exceptions are not thrown at higher level, you should use TaskContinuationOptions.OnlyOnFaulted on the task continuation to check if there was an exception. You can get tasks exceptions at caller's level only with the async keyword not available in .net 4
Handle AggregateExceptions like this:
catch(AggregateException aex)
{
aex.Handle(ex =>
{
// Do some handling and logging
return true;
}
}

Categories