Task continue with not working upon exception - c#

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.

Related

Task swallows the exception thrown

In the method below, when an exception is thrown in the TRY block, it is being swallowed. How can I make it throw the exception so that it gets written to log in the catch block? The log writer works fine. Thanks!
public static bool MonitorQueueEmptyTask(string queueName, CancellationTokenSource tokenSource)
{
try
{
Task<bool> task = Task.Factory.StartNew<bool>(() =>
{
while (!QueueManager.IsQueueEmpty(queueName))
{
if (tokenSource.IsCancellationRequested)
{
break;
}
Thread.Sleep(5000);
throw new Exception("Throwing an error!"); //THIS THROW IS SWALLOWED -- NO LOG WRITTEN ON CATCH
};
return true;
}, tokenSource.Token);
}
catch (Exception ex)
{
WriteExceptionToLog(ex.Stack); //it's not that this method doesn't work. it works fine.
return false;
}
return true;
}
If you want to fire and forget, you can attach a continuation using ContinueWith. The current try-catch will not help you at all, as the exception is encapsulated inside the Task. If this is "fire and forget", than you can log the exception:
public static Task MonitorQueueEmptyTask(
string queueName, CancellationTokenSource tokenSource)
{
return Task.Factory.StartNew<bool>(() =>
{
while (!QueueManager.IsQueueEmpty(queueName))
{
if (tokenSource.IsCancellationRequested)
{
break;
}
Thread.Sleep(5000);
throw new Exception("Throwing an error!");
};
}, tokenSource.Token, TaskCreationOptions.LongRunning).ContinueWith(faultedTask =>
{
WriteExceptionToLog(faultedTask.Exception);
}, TaskContinuationOptions.OnlyOnFaulted);
}
This, in turn, will not propagate the exception after it's thrown, but will provide a mechanism to log the error. If you want the exception to be properly handled, you can register to TaskScheduler.UnobservedTaskException. Additionally, you can set ThrowUnobservedTaskExceptions enabled="true" in your configuration if you want unhandled exceptions to terminate your application. ContinueWith will consider the exception "handled" once you look at the task.Exception property.
The exception is not swallowed; it's just that it doesn't occur on the thread that executes the try/catch block, but on the separate Task thread.
If you don't observe the task's result or exception, when the task is eventually garbage collected, it will throw an exception saying that the task was not observed. Unless you catch that by handling the TaskScheduler.UnobservedTaskException, it will crash the process.
I also had a problem with this, and i really dislike the whole idea of App.config, so can provide another solution to prevent the exceptions disappearing :)
Save the exception then throw it after the Task.Run has completed, e.g.
private async void Function() {
Exception save_exception = null;
await Task.Run(() => {
try {
// Do Stuff
} catch (Exception ex) {
save_exception = ex;
}
}).ContinueWith(new Action<Task>(task => {
if (save_exception != null)
throw save_exception;
// Do Stuff
}));
}

Error handling in Tasks

I have the following code
Task load = Task.Factory.StartNew(() =>
{
Threading.Thread.Sleep(5000);
throw new Exception("bad error");
});
try{
load.Wait();
}catch(AggregateException aex){
MessageBox.Show("Error Caught!");
}
Here as you can see, I create a task and throw an exception.
The exception is then caught on the UI thread. But with this this set up, the UI will be un responsive.
What is the work around for this to make the UI responsive and catch the Exception?
There is a couple of ways to handle this.
You could use ContinueWith and check there, or you could just hook into the global task exception handler TaskScheduler.UnobservedTaskException). (details to come)
ContinueWith for exception handling only:
load.ContinueWith(previousTask =>
{
//exception message here
}, TaskContinuationOptions.OnlyOnFaulted);
or for with a normal try catch:
load.ContinueWith(previousTask =>
{
try
{
previousTask.Result
}
catch(Exception ex){//message here}
});
You'll want to add a continuation to the task, rather than using Wait or any other means of blocking on the task.
load.ContinueWith(t => MessageBox.Show(t.Exception.Message)
, TaskContinuationOptions.OnlyOnFaulted);

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;
}
}

handling exception in Tpl

I have read a lot on how to handle exceptions in TPL but don't really understand.
Lets take this example code:
var task1 = new Task(() => { throw new Exception("Throw 1"); });
var task2 = task1.ContinueWith(t => Console.WriteLine("Catch 1:{0}", t.Exception.Message),
TaskContinuationOptions.OnlyOnFaulted);
var task3 = task2.ContinueWith(t => Console.WriteLine("Continuation"));
task1.Start();
try {
task1.Wait();
}
catch (Exception ex) {
Console.WriteLine("Wait Exception: {0}", ex.Message);
}
I expected this to print
Catch 1
Continuation
But I get
Catch 1
Continuation
Wait Exception
This means that the exception is still considered unhandled when the task completes and the task finalizer will eventually tear down the application.
How do I handle the exception inside the continuation so the finalizer will not throw? At the same time I want the task to remain in the faulted state so wrapping the task in try/catch will not work.
The background is that I want to implement the async event pattern as specified here but with error handling. My complete code looks like this
public IAsyncResult Begin(AsyncCallback callback, object state, Action action) {
var task1 = new Task(action);
var task2 = task1.ContinueWith(t => HandleException(t.Exception),
TaskContinuationOptions.OnlyOnFaulted);
if (callback != null) {
var task3 = task2.ContinueWith(t => callback(t),
TaskScheduler.FromCurrentSynchronizationContext());
var task4 = task3.ContinueWith(t => HandleException(t.Exception),
TaskContinuationOptions.OnlyOnFaulted);
}
task1.Start();
return task;
}
You do your wait on the task that fails, and if you read the documentation on Task.Wait carefully you will see that wait will rethrow the exception in this case.
But if you wait on your task3 everything should work as expected.
Of course you should keep this in mind:
When you use the OnlyOnFaulted option, it is guaranteed that the
Exception property in the antecedent is not null. You can use that
property to catch the exception and see which exception caused the
task to fault. If you do not access the Exception property, the
exception will go unhandled. Also, if you attempt to access the Result
property of a task that has been canceled or has faulted, a new
exception will be raised.
(Reference here)
And finally yet another good source on How to handle exceptions thrown by tasks
I hope this helps.

Prevent Task.ContinueWith on exception

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.

Categories