You probably don't need separate OnlyOnFaulted
and OnlyOnRanToCompletion
handlers, and you're not handling OnlyOnCanceled
. Check this answer for more details.
But when debugging in IDE, A IDE exception message ("Unhandled
exception in user code" ) appears when the control executes the line
You see the exception under debugger because you probably have enabled it in Debug/Exceptions options (Ctrl+Alt+E).
If I continue from there on, the program does not crash and displays
the same output as release mode. Is this proper way to handle
exception?
An exception which was thrown but not handled inside a Task
action will not be automatically re-thrown. Instead, it be wrapped for future observation as Task.Exception
(of type AggregateException
). You can access the original exception as Exception.InnerException
:
Exception ex = task.Exception;
if (ex != null && ex.InnerException != null)
ex = ex.InnerException;
To make the program crash in this case, you actually need to observe the exception outside the task action, e.g. by referencing the Task.Result
:
static void Main(string[] args)
{
// Get the task.
var task = Task.Factory.StartNew<int>(() => { return div(32, 0); });
// For error handling.
task.ContinueWith(t => { Console.WriteLine(t.Exception.Message); },
TaskContinuationOptions.OnlyOnFaulted);
// If it succeeded.
task.ContinueWith(t => { Console.WriteLine(t.Result); },
TaskContinuationOptions.OnlyOnRanToCompletion);
Console.ReadKey();
Console.WriteLine("result: " + task.Result); // will crash here
// you can also check task.Exception
Console.WriteLine("Hello");
}
More details: Tasks and Unhandled Exceptions, Task Exception Handling in .NET 4.5.
Updated to address the comment: here is how I would do this in a UI app with .NET 4.0 and VS2010:
void Button_Click(object sender, EventArgs e)
{
Task.Factory.StartNew<int>(() =>
{
return div(32, 0);
}).ContinueWith((t) =>
{
if (t.IsFaulted)
{
// faulted with exception
Exception ex = t.Exception;
while (ex is AggregateException && ex.InnerException != null)
ex = ex.InnerException;
MessageBox.Show("Error: " + ex.Message);
}
else if (t.IsCanceled)
{
// this should not happen
// as you don't pass a CancellationToken into your task
MessageBox.Show("Canclled.");
}
else
{
// completed successfully
MessageBox.Show("Result: " + t.Result);
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
For as long as you target .NET 4.0 and you want the .NET 4.0 behavior for unobserved exceptions (i.e., re-throw when task gets garbage-collected), you should explicitly configure it in the app.config
:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
<runtime>
<ThrowUnobservedTaskExceptions enabled="true"/>
</runtime>
</configuration>
Check this for more details:
Unobserved task exceptions in .NET4