73

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()?

Sebastian Krysmanski
  • 8,114
  • 10
  • 49
  • 91

3 Answers3

42

Under the Debug menu, select Exceptions.... In the Exceptions dialog, next to the Common Language Runtime Exceptions line check the Thrown box.

For VS2022 ... Select "Debug" "Windows" "Exceptions Settings" and then check the box immediately to the left of Common Language Runtime Exceptions.

Danimal111
  • 1,976
  • 25
  • 31
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • 22
    Ok, I did know that. But then the debugger will break on *all* exceptions, not just on the unhandled ones, right? So it's not exactly what I'm looking for. – Sebastian Krysmanski Aug 07 '13 at 08:19
  • 7
    @SebastianKrysmanski: The exception is handled, though. If you have an `async Task` method, then the exception is caught by the `async` state machine and placed on the returned `Task`. – Stephen Cleary Oct 29 '15 at 00:09
  • 19
    In Visual Studio 2015, the exception settings are found under `Debug` >> `Windows` >> `Exception Settings` (Ctrl+Alt+E) – Frederik Struck-Schøning May 06 '16 at 11:15
  • 1
    @StephenCleary "The exception is handled, though." - yes, but it's not being caught by User-code. Even with "Just My Code" enabled it still thinks that the implicit `catch` inside the async plumbing counts as User-code when it shouldnt. – Dai Jul 24 '20 at 04:34
3

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");
}
Tony
  • 16,527
  • 15
  • 80
  • 134
Jimbob
  • 39
  • 2
  • 2
    What happens if `Task.Delay()` throws a different exception? – Thomas Weller Jul 31 '15 at 11:40
  • Thomas, I was just expanding on the original poster's example. Going off your logic, *anything* can fail - which is true, but we have to answer in context,... so we could go round in circles forever... My answer is in context to having the debugger stop at a desirable point in code where you can then view what the local variables values are and potentially what is causing the Exception. This isn't easily achieved if the exception is thrown outside of the Task (as per OP) as it can become a nightmare to debug. – Jimbob Jul 31 '15 at 19:59
-5

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
     }

});
araknoid
  • 3,065
  • 5
  • 33
  • 35
Craig
  • 7