We are using Tasks in our .Net 4 (no async await available) application and sometimes they are used to launch 'Fire and Forget' operations like the following one:
private void Test()
{
Task task = Task.Factory.StartNew(() =>
{
throw new ApplicationException("Test");
});
}
We want this exception to crash the application without waiting the task (as otherwise it makes no sense to have it in a task, at least in our scenarios) and without waiting the finalizer as we want to shutdown the application when an unexpected error happens to avoid state corruptions (we are saving the state present when the exception happened).
My guess is that somehow we should work with a continuation task but that puts the continuation code inside another task that will not make the application crash so I'm blocked here.
Any help will be very appreciated
Edit: if switching to the ThreadPool the result is the expected one. The following code crashes the application:
ThreadPool.QueueUserWorkItem((c) =>
{
throw new ApplicationException("Test");
});
I finally found how to do it even when it is a bit complicated:
namespace ThreadExceptions
{
using System;
using System.Threading;
using System.Threading.Tasks;
public static class TaskExtensions
{
public static Task ObserveExceptions(this Task task)
{
return task.ContinueWith((t) =>
{
ThreadPool.QueueUserWorkItem((w) =>
{
if (t.Exception != null)
{
foreach (Exception ex in t.Exception.InnerExceptions)
{
throw new TaskException(ex);
}
}
});
}, TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.PreferFairness);
}
}
}
This will make the application crash without waiting for the task. That's was I was looking for.
Try this solution using FailFast
This method terminates the process without running any active try/finally blocks or finalizers.
private void Test()
{
Task task = Task.Factory.StartNew(() =>
{
Environment.FailFast("Test", new ApplicationException("Test"));
});
}
You could write your own Task
class which wraps the various Task
methods that you want to use, and add the exception handling to it.
For example:
public static class TaskWithExceptionHandling
{
public static Task StartNew(Action action)
{
var task = Task.Factory.StartNew(action);
task.ContinueWith(exceptionHandler, TaskContinuationOptions.OnlyOnFaulted);
return task;
}
private static void exceptionHandler(Task task)
{
// Handle unhandled aggregate task exception from 'task.Exception' here.
Console.WriteLine("Exception: " + task.Exception.GetBaseException().Message);
}
}
Which you would substitute for the Task
class like so:
Task task = TaskWithExceptionHandling.StartNew(() =>
{
throw new InvalidOperationException("Test exception");
});
Console.ReadLine();
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