When a debugger is attached to a .NET process, it (usually) stops when an unhandled exception is thrown.
However, this doesn't seem to work when you're in an async method.
The scenarios I've tried before are listed in the following code:
class Program
{
static void Main()
{
// Debugger stopps correctly
Task.Run(() => SyncOp());
// Debugger doesn't stop
Task.Run(async () => SyncOp());
// Debugger doesn't stop
Task.Run((Func<Task>)AsyncTaskOp);
// Debugger stops on "Wait()" with "AggregateException"
Task.Run(() => AsyncTaskOp().Wait());
// Throws "Exceptions was unhandled by user code" on "await"
Task.Run(() => AsyncVoidOp());
Thread.Sleep(2000);
}
static void SyncOp()
{
throw new Exception("Exception in sync method");
}
async static void AsyncVoidOp()
{
await AsyncTaskOp();
}
async static Task AsyncTaskOp()
{
await Task.Delay(300);
throw new Exception("Exception in async method");
}
}
Am I missing something? How can I make the debugger to break/stop on the exception in AsyncTaskOp()?
Under the Debug menu, select Exceptions.... In the Exceptions dialog, next to the Common Language Runtime Exceptions line check the Thrown box.
I would like to hear if anyone found out how to get around this issue? Perhaps a setting in latest visual studio...?
A nasty but workable solution (in my case) was to throw my own custom Exception and then modify Stephen Cleary's answer:
Under the Debug menu, select Exceptions (You can use this Keyboard shortcut Control + Alt + E)... In the Exceptions dialog, next to the Common Language Runtime Exceptions line check the Thrown
box.
to be more specific i.e., add your custom Exception into the list, and then tick its "Thrown" box.
E.g:
async static Task AsyncTaskOp()
{
await Task.Delay(300);
throw new MyCustomException("Exception in async method");
}
I have wrapped the anonymous delegate in a try/catch inside the Task.Run(() =>.
Task.Run(() =>
{
try
{
SyncOp());
}
catch (Exception ex)
{
throw; // <--- Put your debugger break point here.
// You can also add the exception to a common collection of exceptions found inside the threads so you can weed through them for logging
}
});
Related
I have a hard time understanding how async/await works in various non-happy-path cases. For example, I have the following code:
class Program
{
static void Main(string[] args)
{
Do();
Console.ReadLine();
}
private static void Do()
{
TaskScheduler.UnobservedTaskException += (s, e) =>
{
Console.WriteLine($"Unobserved Exception : {e.Exception.Message}");
e.SetObserved();
};
try
{
ThrowsAsync();
}
catch (Exception ex)
{
Console.WriteLine($"Caught in try/catch : {ex.Message}");
}
}
private static async Task ThrowsAsync()
{
Console.WriteLine("Throwing");
throw new Exception("FAILURE");
}
}
There are two things that I do not understand:
The ThrowsAsync method is async, however, it does not contain any await. I would assume that in such a case the method would execute like a "normal" synchronous method. However, the exception that it throws is never caught in the catch block.
Trying to somehow catch the exception, I added the handler for TaskScheduler.UnobservedTaskException. However, it is never executed. Why is that?
I know that the exception would be caught if I awaited ThrowsAsync. However, I'm experimenting to get a better understanding of how it works.
I'm running that code using .NET 5 and Linux-based OS.
As described for example in this blog post by Stephen Cleary - the state machine for async methods will capture exceptions from your code and place them on the returned task, i.e. method invocation will not throw, you will be able to catch exception if await the result.
As for TaskScheduler.UnobservedTaskException - check out this answer and be sure to run code in Release mode.
i need help with catching exceptions in C#. I have a Windows service which is acting like a wrapper for other modules, so to not have multiple Windows Services i start all modules/agents thats how we call them in that Wrapper Windows Service. Each of this 'agent' is started in a own Task. I am not in control what the agent itself is doing so it can be and will from time to time is such a agent starting also a task or thread and if there an exception is getting thrown, i am not able to catch it. I tried different things but was not able to do so. So if such a exception occurs in production my whole service is crashing and all agents with it, which is a nightmare. I try to simplify it with an example code:
public class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
AppDomain.CurrentDomain.UnhandledException += (o, e) =>
{
Console.WriteLine("CurrentDomain Unhandled Exception: {0}", e.ExceptionObject);
};
TaskScheduler.UnobservedTaskException += (s, e) =>
{
Console.WriteLine("TaskScheduler.UnobservedTaskException Unhandled Exception: {0}", e.Exception);
e.SetObserved();
};
Task.Factory.StartNew(() =>
{
Task.Factory.StartNew(() => throw new Exception("I am a exception ! Catch me !"));
}, TaskCreationOptions.LongRunning)
.ContinueWith((t) =>
t.Exception.InnerExceptions.ToList().ForEach(e => Console.WriteLine("Error executing task.{0}", e)),
TaskContinuationOptions.OnlyOnFaulted);
Console.WriteLine("If you read this, application is not crashed!");
Console.ReadKey();
Task.Factory.StartNew(() =>
{
throw new Exception("I am a exception ! Catch me !");
});
}
}
So how to catch the exception ? It will not get fetched by any of my handlers.
Important is that i have no influence of that part of code, thats my 'agent' :
Task.Factory.StartNew(() => throw new Exception("I am a exception ! Catch me !"));
Everything else i am able to change.
Edit:
unfortunately provided solution seems to not work for me. I am still not able to catch the exception which occurs. Maybe its getting more clear when i show my original code:
private async Task StartAgent(IAgent agent)
{
_logger.LogInfo("Agent starting with instanceId {0}", agent.GetInstanceGuid());
if (agent == null)
{
throw new ArgumentNullException("agent");
}
try
{
Task task = await Task.Factory.StartNew(async () =>
{
agent.Start();
}, TaskCreationOptions.LongRunning);
await task.ContinueWith((t) =>
{
var aggException = t.Exception.Flatten();
foreach (var exception in aggException.InnerExceptions)
_logger.LogError("Error executing agent task.{0}", exception, t.Id);
}, TaskContinuationOptions.OnlyOnFaulted);
_agents[agent.GetInstanceGuid()].Task = task;
_agents[agent.GetInstanceGuid()].LastTaskStatus = task.Status;
}
catch (Exception e)
{
_logger.LogError("Exception in Agent Task.",e);
}
}
So the agent.Start() is what i am calling in the task everything what happens inside i don't know. The agent can create tasks, threads everything he wants. Start() is also void and i can't change the interface to await it.
[Task.Factory.StartNew] is wrapped in a void method.
Well, then, the code is deliberately ignoring all exceptions. This kind of "fire and forget" is problematic precisely because it ignores the returned task. All exceptions are placed on that task, which is then ignored.
TaskScheduler.UnobservedTaskException catches it
UnobservedTaskException or AppDomain.FirstChanceException are your only real options. Neither of these are particularly nice (i.e., they're global handlers), but they're your only option because the code outside your control is explicitly ignoring exceptions.
Thanks for all the answers. I found a easy solution now which works for me. All i had to do is adding in my 'runtime' part of my app.config this flag
<legacyUnhandledExceptionPolicy enabled="1" />
Like described here: How to prevent an exception in a background thread from terminating an application?
I had the problem even if i was able to catch my exception my service still stops afterwards.
When awaiting a faulted task (one that has an exception set), await will rethrow the stored exception. If the stored exception is an AggregateException it will rethrow the first and discard the rest.
How can we use await and at the same time throw the original AggregateException so that we do not accidentally lose error information?
Note, that it is of course possible to think of hacky solutions for this (e.g. try-catch around the await, then call Task.Wait). I really wish to find a clean solution. What is the best-practice here?
I thought of using a custom awaiter but the built-in TaskAwaiter contains lots of magic that I'm not sure how to fully reproduce. It calls internal APIs on TPL types. I also do not want to reproduce all of that.
Here is a short repro if you want to play with it:
static void Main()
{
Run().Wait();
}
static async Task Run()
{
Task[] tasks = new[] { CreateTask("ex1"), CreateTask("ex2") };
await Task.WhenAll(tasks);
}
static Task CreateTask(string message)
{
return Task.Factory.StartNew(() => { throw new Exception(message); });
}
Only one of the two exceptions is thrown in Run.
Note, that other questions on Stack Overflow do not address this specific problem. Please be careful when suggesting duplicates.
I disagree with the implication in your question title that await's behavior is undesired. It makes sense in the vast majority of scenarios. In a WhenAll situation, how often do you really need to know all of the error details, as opposed to just one?
The main difficulty with AggregateException is the exception handling, i.e., you lose the ability to catch a particular type.
That said, you can get the behavior you want with an extension method:
public static async Task WithAggregateException(this Task source)
{
try
{
await source.ConfigureAwait(false);
}
catch
{
// source.Exception may be null if the task was canceled.
if (source.Exception == null)
throw;
// EDI preserves the original exception's stack trace, if any.
ExceptionDispatchInfo.Capture(source.Exception).Throw();
}
}
I know I'm late but i found this neat little trick which does what you want. Since the full set of exceptions are available with on awaited Task, calling this Task's Wait or a .Result will throw an aggregate exception.
static void Main(string[] args)
{
var task = Run();
task.Wait();
}
public static async Task Run()
{
Task[] tasks = new[] { CreateTask("ex1"), CreateTask("ex2") };
var compositeTask = Task.WhenAll(tasks);
try
{
await compositeTask.ContinueWith((antecedant) => { }, TaskContinuationOptions.ExecuteSynchronously);
compositeTask.Wait();
}
catch (AggregateException aex)
{
foreach (var ex in aex.InnerExceptions)
{
Console.WriteLine(ex.Message);
}
}
}
static Task CreateTask(string message)
{
return Task.Factory.StartNew(() => { throw new Exception(message); });
}
Here is a shorter implementation of Stephen Cleary's WithAggregateException extension method:
public static async Task WithAggregateException(this Task source)
{
try { await source.ConfigureAwait(false); }
catch when (source.IsCanceled) { throw; }
catch { source.Wait(); }
}
public static async Task<T> WithAggregateException<T>(this Task<T> source)
{
try { return await source.ConfigureAwait(false); }
catch when (source.IsCanceled) { throw; }
catch { return source.Result; }
}
This approach is based on a suggestion by Stephen Toub in this API proposal in GitHub.
Update: I added a special handling of the cancellation case, to prevent the awkwardness of propagating an AggregateException that contains an OperationCanceledException. Now the OperationCanceledException is propagated directly, and the Task.IsCanceled status is preserved. Kudos to #noseratio for pointing out this flaw in the comments of this answer. Of course now this implementation is not much shorter than Stephen Cleary's approach!
Exception Handling (Task Parallel Library)
I could say more but it would just be padding. Play with it, it does work as they say. You just have to be careful.
maybe you want this
God (Jon Skeet) explains await exception handling
(personally i shy away from await, but thats just my preference)
in response to comments (too long for a comment reply)
Then use threads as your starting point for an analogous argument as the best practises there will be the source of ones for here.
Exceptions happily get swallowed unless you implement code to pass them out (for instance the async pattern that the await is preumably wrapping ... you add them to an event args object when you raise an event). When you have a scenario where you fire up an arbitrary number of threads and execute on them you have no control over order or the point at which you terminate each thread. Moreover you would never use this pattern if an error on one was relevant to another. Therefor you are strongly implying that execution of the rest is completley independent - IE you are strongly implying that exceptions on these threads have already been handled as exceptions. If you want to do something beyond handling exceptions in these threads in the threads they occur in (which is bizzarre) you should add them to a locking collection that is passed in by reference - you are no longer considering exceptions as exceptions but as a piece of information - use a concurrent bag, wrap the exception in the info you need to identify the context it came from - which would of been passed into it.
Don't conflate your use cases.
I don't want to give up the practice to only catch the exceptions I expect. This leads me to the following extension method:
public static async Task NoSwallow<TException>(this Task task) where TException : Exception {
try {
await task;
} catch (TException) {
var unexpectedEx = task.Exception
.Flatten()
.InnerExceptions
.FirstOrDefault(ex => !(ex is TException));
if (unexpectedEx != null) {
throw new NotImplementedException(null, unexpectedEx);
} else {
throw task.Exception;
}
}
}
The consuming code could go like this:
try {
await Task.WhenAll(tasks).NoSwallow<MyException>();
catch (AggregateException ex) {
HandleExceptions(ex);
}
A bone-headed exception will have the same effect as in synchronous world, even in case it is thrown concurrently with a MyException by chance. The wrapping with NotImplementedException helps to not loose the original stack trace.
Extension that wraps original aggregation exception and doesn't change return type, so it can still be used with Task<T>
public static Task<T> UnswallowExceptions<T>(this Task<T> t)
=> t.ContinueWith(t => t.IsFaulted ? throw new AggregateException("whatever", t.Exception) : t.Result);
Example:
Task<T[]> RunTasks(Task<T>[] tasks) =>
Task.WhenAll(CreateSometasks()).UnswallowExceptions();
try
{ var result = await CreateTasks(); }
catch(AggregateException ex) { } //ex is original aggregation exception here
NOTE This method will throw if task was canceled, use another approach if cancelling is important for you
Please, observe this simple code:
try
{
var t = Task.Factory.StartNew<bool>(() => { throw new Exception("aaa"); });
t.ContinueWith(_ => {}, TaskContinuationOptions.OnlyOnRanToCompletion).Wait();
}
catch (Exception exc)
{
Debug.WriteLine(exc);
}
I assumed that if t has an exception associated with it, then this exception will be rethrown as is by Wait(). However, the presence of the success only continuation seems to change this behavior. What is thrown instead is a "A task was canceled" exception.
Indeed, chaining a TaskContinuationOptions.NotOnRanToCompletion completion handler just before Wait() reveals that the task passed to it is not faulted, but cancelled:
t.ContinueWith(_ => { }, TaskContinuationOptions.OnlyOnRanToCompletion)
.ContinueWith(t2 => Debug.Assert(t2.IsCanceled), TaskContinuationOptions.NotOnRanToCompletion)
.Wait();
This is all a bit strange. It means, I cannot just chain my happy path completion handlers letting any exceptions just propagate to the ultimate rendezvous with the waiting thread.
What am I missing here?
NOTE
I am limited to .NET 4.0, so no await and async keywords.
What am I missing here?
You are missing .NET 4.5. Tasks are still useful without the await and async keywords, but if you want the "happy path" behavior you're talking about, you'll need to upgrade (see update below).
Because tasks are more complicated than standard run-through code, and because they can be joined together in various ways, you'll need to ask for the exception directly from the Task, rather than the exception thrown by the call to .Wait().
var t = Task.Factory.StartNew<bool>(() => { throw new Exception("aaa"); });
try
{
t.ContinueWith(_ => {}, TaskContinuationOptions.OnlyOnRanToCompletion)
.Wait();
}
catch (AggregateException exc)
{
Debug.WriteLine(exc.InnerExceptions[0]);// "A task was canceled"
Debug.WriteLine(t.Exception.InnerExceptions[0]);// "aaa"
}
Update: If you are using Visual Studio 2012, it appears that you can use the async and await keywords without upgrading to 4.5. Thanks to #zespri for pointing this out.
Update 2: If you want to catch and log the appropriate exception at the top level, just make a habit of wrapping your .Wait() methods in try/catch blocks, wrap the given exception.
try
{
t.Wait();
}
catch (AggregateException exc)
{
throw new Exception("Task Foo failed to complete", t.Exception);
}
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.