Debugging Asynchronous Code in Visual Studio 2013- Call Stack enhancements
Developers typically rely on the Call Stack window to tell them how their application got to their current location, but this was not the case for asynchronous calls. The new call stack window for asynchronous debugging provides additional stack frames to aid in understanding how the program reached a location inside an asynchronous call.
The following example in C++ demonstrates a challenge presented while debugging asynchronous code.
In this example, the ProcessFile function, which creates an asynchronous task with a continuation lambda, is called from two different places within the application (SearchCustomFile and SearchTestFile). The problem here is that when you run this code and the exception is thrown, you cannot quickly determine how you got there because the execution path could have been through either function. Since the task is created on a new thread, it has no information about the call stack that existed when it was scheduled and, therefore, have no information about the code sequence leading up its creation. The call stack below shows this experience in Visual Studio 2012 and Windows 8.
You can see that you hit an exception within the task continuation, but the call stack tells you nothing about which code path triggered the exception. To deal with this problem, we have added a new feature to the call stack window that provides context to the code sequence leading up to an asynchronous task. The Call Stack window for C++ will now show the frame(s) that existed on the call stack when the task was created. These additional frames are added below the task’s actual call stack and are separated from the actual call stack by an annotated frame named “[Async Call]”. As with any other frame on the call stack, double-clicking on the added frames will navigate to that frame’s source code, if available. A screenshot of the new call stack window is shown below. To minimize performance impact, the number of added frames is limited to 10 by default when in Debug mode (1 in Release mode). For situations warranting more frames, this limit may be changed by defining the PPL_TASK_SAVE_FRAME_COUNT macro in the source code with the number of frames needed.
With the new information presented in the call stack window under the “[Async Call]” annotated frame combined with the new Just My Code feature for C++, I am able to immediately discover where I am and how I got there when the First-Chance exception is caught. This will, ultimately, reduce the time it takes to find the root cause of the problem in the code.
Now, look at the call stack you can see across the asynchronous calls to see how your own code led to the current state of the app. Double-clicking on the frame in default.js takes you to your own code that was the source of the issue.
C# and VB
Consider the following code.
private async void Button_Click(object sender, RoutedEventArgs e)
private async Task DoWork(int a)
int i = a*a;
private async Task GetFile(int a)
StorageFolder folder = KnownFolders.DocumentsLibrary;
file = await folder.GetFileAsync(a.ToString() + ".txt");
And let’s say that you have a breakpoint set in the GetFile method. When you stop at that breakpoint, you will get the following call stack.
We would love to hear any questions or comments you have in the comments below or on our MSDN forum.