10

Say I have the following code:

async void buttonClick(object sender, RoutedEventArgs e)
{
    await nested1();
}

async Task nested1()
{
    await nested2();
}

async Task nested2()
{
    await nested3();
}

async Task nested3()
{
    await Task.Delay(1000);
    throw new Exception("Die");  // <-- I want Visual Studio to break on this line
}

How can I make Visual Studio break on the indicated line only when the exception is unhandled?


Normally when the exception is thrown, Visual Studio will break here in App.g.i.cs:

enter image description here

If I then enable "Just my code" in the debugger options, it will break here instead:

enter image description here

Getting close. If I then check System.Exception under the "Thrown" column in the Exceptions window (Ctrl+Alt+E), it will break exactly where I want:

enter image description here

but now Visual Studio will break on all thrown exceptions, not just unhandled ones. Is there any way to get Visual Studio to break at the most logical line of code only for unhandled exceptions, just like it would in regular non-async code? If this behavior is not possible, then:

  • Why is it not possible?
  • How can I identify the line of code that has thrown the exception, whether that be a throw statement of my own code, or a framework method call that has thrown an exception?

I've used 3 nested functions here in this example to emphasize that my code may be complex with many branches and nested method calls, and identifying the problematic line of code is difficult if Visual Studio doesn't break on the innermost line of code.

Decade Moon
  • 32,968
  • 8
  • 81
  • 101
  • 1
    Related - http://stackoverflow.com/questions/18958950/how-can-i-make-vs-break-on-exceptions-in-an-async-task-without-breaking-on-all. – Eugene Podskal Oct 07 '14 at 08:24

2 Answers2

10

I think I may have discovered the answer to my question.

First, I uncheck System.Exception under the "Thrown" column in the exceptions window (Ctrl+Alt+E). I do this because I don't want Visual Studio to break on all exceptions, only unhandled ones.

Second, I keep "Just my code" enabled in the debugger options.

Now, when the debugger breaks, it will break here:

enter image description here

as per the screenshot in my question. But if I inspect the call stack:

enter image description here

I can actually see where the exception originated from (in nested3(), line 46). If I click this entry in the call stack window, Visual Studio will jump to the correct line, and the "Locals" window will even show me the values of local variables in that frame. Cool! I think this is what I wanted.

Decade Moon
  • 32,968
  • 8
  • 81
  • 101
  • 2
    Downvoter: please explain why this answer is incorrect/poor. It'll help me and the community. – Decade Moon Oct 07 '14 at 11:33
  • Enabling Just My Code does it! – Roman Starkov Apr 05 '16 at 10:03
  • doesn't work for my case, I let async method encounter some error, but I am ignoring in in the calling method. So Call Stack doesn't show anything. If it wasn't for this defected await/asyn VS would stop in the async method at the error – Toolkit Oct 30 '19 at 10:10
4

It's not possible.

Why is it not possible?

Because it's not done yet. async is still getting better tooling support with every release, and I do expect this behavior to be added sooner or later.

How can I identify the line of code that has thrown the exception, whether that be a throw statement of my own code, or a framework method call that has thrown an exception?

Visual Studio 2013 does have the ability to view asynchronous causality stacks in the debugger. If you want similar behavior at runtime, then you can use my async diagnostics package.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Thanks, those links were helpful. I guess I was just confused because Visual Studio was breaking at a different location to where the exception was initially raised. I think this has something to do with the exception being captured in the `Task` object and then raised only once the task has been `await`ed. In this case, the `async void buttonClick` method doesn't return a `Task`, so the `await nested1()` line is where the exception goes unhandled and cannot be passed to the caller. I think I'll go read some MSDN articles... – Decade Moon Oct 07 '14 at 12:49
  • I just tried Decade Moon's answer (enable Just My Code) and the debugger stopped at exactly the right place in the async code, so I would say it is possible. It sometimes stops on the parent await rather than the actual exception though, I haven't figured out the specifics yet. – Roman Starkov Apr 05 '16 at 10:12