Why is this exception not caught? - c#

I'm trying to run the following code:
class Program
{
static void Main(string[] args)
{
var task = Task.Factory.StartNew(() =>
{
throw new ApplicationException("message");
});
try
{
task.ContinueWith(t => Console.WriteLine("End"));
}
catch (AggregateException aex)
{
Console.Write(aex.InnerException.Message);
}
}
}
I expected that the Exception would be caught in the following location:
catch (AggregateException aex)
{
Console.Write(aex.InnerException.Message);
}
But this is not happening. Why is this so?

You're just printing out the task - which won't even have completed yet.
Printing out the task doesn't wait for it to complete, or try to fetch the value.
If you change your code to:
try
{
task.Wait();
}
... then I'd expect it to catch the exception.
(I was previously using Task<T>.Result, but I notice this is a task with no return value, so it would just be the non-generic Task.)

The way Task works, the code that ends up calling the delegate you pass to StartNew will be caught, eventually, and the Exception will be stored in an instance field of the task. That exception can be inspected by looking at the task.Exception property. The line Console.WriteLine(task) is just calling task.ToString internally. That method won't result in the exception being thrown or re-thrown.
However, under certain circumstances the exception that is caught will be re-thrown. Two examples are when accessing Result and calling Wait, as well as when you await a task in C# 5.0.
The following code:
try
{
task.Wait();
}
catch (AggregateException aex)
{
Console.Write(aex.InnerException.Message);
}
Will result in the stored exception being re-thrown and the exception message will be printed.

AggregateException and ApplicationException are both children of the same class, System.Exception.
AggregateException is-not a ApplicationException

Cause your statement is not in the try, but before it... catch will catch every exception from within the try curly brackets...

Related

Exception handling : Thread v/s Task

Thread version results in unhandled exception, which crashes the app but the task version doesn't. Both are running exactly the same method Can someone explain the reason for this difference in exception behavior ?
Thread version:
try
{
new Thread(new ThreadStart(DoWork)).Start(); // do work throws exception
}
catch (Exception e)
{
Console.WriteLine(e);
}
static void DoWork()
{
Console.WriteLine("in thread");
throw new Exception();
}
Task version:
var errorTask = Task.Factory.StartNew<Func<string>>(() =>
{
Console.WriteLine("in task");
throw new Exception();
});
try
{
string result = errorTask.Result();
}
catch (Exception e)
{
Console.WriteLine(e);
}
Thread.Start starts new thread, but you're handling exception in another thread:
try
{
// DoWork throws exception in new thread;
// threads don't catch exceptions out-of-the-box
new Thread(new ThreadStart(DoWork)).Start();
}
catch (Exception e)
{
// you're handling exception in "old" thread
Console.WriteLine(e);
}
Task.Factory.StartNew starts new task. Task catches exception inside it to set its Status property:
var errorTask = Task.Factory.StartNew<Func<string>>(() =>
{
Console.WriteLine("in task");
// this exception will be caught in Task's base code,
// since tasks catch exceptions thrown by task methods;
// note, that this will be wrapped into AggregateException
throw new Exception();
});
when you're trying to get Task.Result, and task is in faulted state, it just re-throws exception:
// this will re-throw exception in calling thread
string result = errorTask.Result;
That's why your second catch catches it.
To shed some light on the topic one could consult the documentation for Task.Result<TResult>() (or the one for Task.Wait() for what it's worth).
Under thrown exceptions (particularly AggregateException) is says
An exception was thrown during the execution of the task. The AggregateException.InnerExceptions collection contains information about the exception or exceptions.
A Task is kind of a managed thread (in very simple terms) which gives us some merits, e.g. this exception handling when accessing Result or Wait (or using await). On the other hand a Thread will execute separately from the method you are calling it from. You start the thread an (virtually) immediately leave the try / catch block. There is no way to know for the thread that there is an associated try / catch. Basically the thread does not know anything about the calling function. The other way round, if the calling function blocked its own thread to wait for the thread it created, just to make use of the try / catch this would basically render creating new threads useless.

Where to catch exception in async code?

Task task = AsyncMethod();
// do other stuff
await task;
AsyncMethod() can throw exceptions. Do I put the try-catch around the method invocation, the await, or both?
To avoid the whole debate of where the exception handling should happen, I'll just slightly change your question to: where is it possible to catch exceptions thrown from the AsyncMethod method.
The answer is: where you await it.
Assuming your AsyncMethod method looks something like this:
private async Task AsyncMethod()
{
// some code...
throw new VerySpecificException();
}
... then you can catch the exception this way:
Task task = AsyncMethod();
// do other stuff
try
{
await task;
}
catch(VerySpecificException e) // nice, I can use the correct exception type here.
{
// do something with exception here.
}
Just test it, and you will see how the await keyword does all the work of unwrapping and throwing the exception from the returned Task in a way that it feels very natural to code the try-catch block.
Relevant documentation: try-catch.
Notice what the Exceptions in Async Methods section says:
To catch the exception, await the task in a try block, and catch the exception in the associated catch block.

How to catch Exception at another thread

I try to catch exceptions from another thread, but can't.
static void Main(string[] args)
{
try
{
Task task = new Task(Work);
task.Start();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
Console.WriteLine();
}
public static void Work()
{
throw new NotImplementedException();
}
I write try-catch and at method too, but nothing happens.
Please,tell me how to know that exception throw?
Maybe you could show me some example code.
Your code may not raise the exception as the main method will executes too fast and the process will terminate before you got the exception
Here how it would look your code
static void Main(string[] args)
{
Task task = new Task(Work);
task.Start();
var taskErrorHandler = task.ContinueWith(task1 =>
{
var ex = task1.Exception;
Console.WriteLine(ex.InnerException.Message);
}, TaskContinuationOptions.OnlyOnFaulted);
//here you should put the readline in order to avoid the fast execution of your main thread
Console.ReadLine();
}
public static void Work()
{
throw new NotImplementedException();
}
Try to take a look at ContinueWith
The OnlyOnFaulted member of the TaskContinuationOptions enumeration
indicates that the continuation should only be executed if the
antecedent task threw an exception.
task.ContinueWith((Sender) =>
{
////This will be called when error occures
Sender.Result
}, TaskContinuationOptions.OnlyOnFaulted);
Your try/catch wouldn't work. For one reason : because you could very well have gone out of the try block before the exception is thrown, as the Task is done on another thread.
With a Task, there are two ways to get the exceptions.
The first one is to use task.Wait(); in your try block. This method will rethrow any exception thrown by the task.
Then, any exception will be handled on the calling thread in the catch block.
The second one is to use the ContinueWith method. This won't block your calling thread.
task.ContinueWith(t =>
{
// Here is your exception :
DoSomethingWithYour(t.Exception);
}, TaskContinuationOptions.OnlyOnFaulted);
Note the following will block the main thread since Wait is employed.
try
{
Task task = Task.Factory.StartNew(Work);
task.Wait();
}
catch (AggregateException ex)
{
Console.WriteLine(ex.ToString());
}

Why is only one from many exceptions from child tasks always propagated?

I am struggling to better grasp the rationale of exception and error handling in TPL (and with some more luck in .NET 4.5 async/await tasks)
The slightly modified from my earlier question "How to better understand the code/statements from "Async - Handling multiple Exceptions" article?" C# console app code running 2 detached inner nested attached (dependent) child (Update: sorry, started one question but ended by another!) tasks:
class Program
{
static void Main(string[] args)
{ Tst();
Console.ReadLine();
}
async static Task Tst()
{
try
{
await Task.Factory.StartNew
(() =>
{
Task.Factory.StartNew
( () => {
Console.WriteLine("From 1st child");
throw new NullReferenceException();
}
, TaskCreationOptions.AttachedToParent
);
Task.Factory.StartNew
( () =>
{
Console.WriteLine("From 2nd child");
throw new ArgumentException();
}
,TaskCreationOptions.AttachedToParent
);
}
);
}
catch (AggregateException ex)
{
Console.WriteLine("** {0} **", ex.GetType().Name);
foreach (var exc in ex.Flatten().InnerExceptions)
{
Console.WriteLine(exc.GetType().Name);
}
}
catch (Exception ex)
{
Console.WriteLine("## {0} ##", ex.GetType().Name);
}
}
produces output that alternates (non-deterministically) between:
From 1st child
From 2nd child
** AggregateException **
ArgumentException
and
From 1t child
From 2nd child
** AggregateException **
NullReferenceException
Seems like always one and only one exception from one of a child tasks always propagated/caught.
Why is only one exception propagated/caught?
I'd have better understood if none or rather all exceptions from child tasks are always caught
Is it possible, in this situation, that both or none exception will be caught?
You should not mix parent/child tasks with async. They were not designed to go together.
svick already answered this question as part of his (correct) answer to your other question. Here's how you can think of it:
Each inner StartNew gets one exception, which is wrapped into an AggregateException and placed on the returned Task.
The outer StartNew gets both AggregateExceptions from its child tasks, which it wraps into another AggregateException on its returned Task.
When you await a Task, the first inner exception is raised. Any others are ignored.
You can observe this behavior by saving the Tasks and inspecting them after the exception is raised by await:
async static Task Test()
{
Task containingTask, nullRefTask, argTask;
try
{
containingTask = Task.Factory.StartNew(() =>
{
nullRefTask = Task.Factory.StartNew(() =>
{
throw new NullReferenceException();
}, TaskCreationOptions.AttachedToParent);
argTask = Task.Factory.StartNew(() =>
{
throw new ArgumentException();
}, TaskCreationOptions.AttachedToParent);
});
await containingTask;
}
catch (AggregateException ex)
{
Console.WriteLine("** {0} **", ex.GetType().Name);
}
}
If you put a breakpoint on WriteLine, you can see that the exceptions from both child tasks are being placed on the parent task. The await operator only propagates one of them, so that's why you only catch one.
From what I can deduce the reason this occurs is that the await signals that task to wait for the task to finish. When an exception is thrown, the task is finished (since an exception crashes it) and the exception propagates outwards to your async function where it will be caught. This means that you will always catch one exception with this setup.
To always catch both, remove await and instead use Task.Factory.StartNew(..).Wait(); The Wait function will keep a count of all child processes and will not return until all of them have finished. Since multiple exceptions are thrown (one from each child) they are bundled in a new AggregateException, which later is caught and its children are flattened and the inner exceptions are printed. This should give you the output:
From 1st child
From 2nd child
** AggregateException **
ArgumentException
NullReferenceException

is it possible to catch when any Task terminates due exception and log?

Is it possible to catch when any Task terminates due exception and log? I've added CurrentDomain_UnhandledException handling but this doesn't help.
I create tasks using Task.Factory.StartNew() as usual. When somewhere inside such task exception occurs it crashes silently (but it supposed to work forever, i'm also using LongRunning option). So I want to be notified about such behavior.
Ideallly I want to set some option somewhere to be notified when any Task crashes due exception.
If it is not possible then likely I should add something to each Task I create? Of course I can just add big try{} finally{} block inside each Task, but probably there are better solutions?
Assuming you have a Test as Task to run:
static int Test()
{
throw new Exception();
}
First Approach - Process exception in the caller's thread:
Task<int> task = new Task<int>(Test);
task.Start();
try
{
task.Wait();
}
catch (AggregateException ex)
{
Console.WriteLine(ex);
}
Note: The exception will be of type AggregateException. All actual exceptions are available through ex.InnerExceptions property.
Second Approach - Process exception in some task's thread:
Define the ExceptionHandler this way:
static void ExceptionHandler(Task<int> task)
{
var ex = task.Exception;
Console.WriteLine(ex);
}
Usage:
Task<int> task = new Task<int>(Test);
task.ContinueWith(ExceptionHandler, TaskContinuationOptions.OnlyOnFaulted);
task.Start();
Reference: How to: Handle Exceptions Thrown by Tasks
For tasks that you create yourself, it's reasonably simple: create your own methods which call Task.Factory.StartNew(), but then also call Task.ContinueWith(loggingDelegate, TaskContinuationOptions.OnlyOnFaulted before returning the task.
The problem is that that won't add a fault handler for tasks created by other bits of infrastructure - including by async methods in C# 5. It still might be useful to you though.
You can also use TaskScheduler.UnobservedTaskException, but as per the name that will only be called for exceptions which aren't already observed by something else. (Again, that may be fine for you...)
You can use an extension method that performs an operation when an exception has ocurred.
This happens when the Task gets Faulted. So if it has another tasks to continue with, the next one can check if the previous task was faulted and Log the exception.
I usually use this methods:
//If you want to chain more tasks..
public static Task<T> Continue<T>(this Task<T> task, Action<T> action)
{
if (!task.IsFaulted)
{
task.ContinueWith((t) => action(t.Result), TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion);
}
return task;
}
public static Task OnException(this Task task, Action<Exception> onFaulted)
{
task.ContinueWith(c =>
{
var excetion = c.Exception;
onFaulted(excetion);
},
TaskContinuationOptions.OnlyOnFaulted |
TaskContinuationOptions.ExecuteSynchronously);
return task;
}
So you can use:
Task.Factory.StartNew(...).OnException(ex => Log(ex));
Hope it helps.
Wrap your task.Wait() in a try/catch block and catch AggregateException. Something like this -
Task<string[]> task1 = Task<string[]>.Factory.StartNew(() => GetAllFiles(path));
// Use this line to throw an exception that is not handled.
try
{
task1.Wait();
}
catch (AggregateException ae)
{
ae.Handle((x) =>
{
if (x is UnauthorizedAccessException) // This we know how to handle.
{
Console.WriteLine("You do not have permission to access all folders
in this path.");
Console.WriteLine("See your network administrator or try
another path.");
return true;
}
return false; // Let anything else stop the application.
});
}
Details can be found here - Handle exceptions thrown by Task.
You can create a OnlyOnFaulted continuation on your Task which observes the exception and logs/reports the problem.
t.ContinueWith(task =>
{
// Report and log error
}, System.Threading.CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.FromCurrentSynchronizationContext());
The above code will run the task on the UI thread because of TaskScheduler.FromCurrentSynchronizationContext(). This may be necessary if you are using winforms and need to notify the user.

Categories

Resources