Learn to use Visual Studio, Visual Studio Online, Application Insights and Team Foundation Server to decrease rework, increase transparency into your application and increase the rate at which you can ship high quality software throughout the application lifecycle
More videos »
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.
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.
Collapsing the managed callstack for async methods like that would be very helpful. Having three rows for a resumed async method does seem a little extraneous, though, especially if you nest async calls several levels deep.
Awesome! Debugging async code is definitely a challenge and every little bit of information that the debugger can provide about the context well help immensely.
This is really great, but I do have a question. I have Visual Studio 2012 Update 3 as well as Visual Studio 2013 Preview. I have tried out the C# examples in both Visual Studio editions, but the call stack result was the same. What am I missing here?
Which version of Windows are you using? These improvements require both Visual Studio 2013 and Windows 8.1 because there are changes in both to make this scenario work.
Jaliya, are you on Windows 8.1 (free upgrade to Win 8) ?
@Brad Sullivan and @DanielMoth
Yes, I am on Windows 8.1 Preview. On top of that I have Visual Studio 2012 Update 3 and 2013 Preview. The result on both call stack windows is same as in last image(clip_image013). What I thought was since I have update 3 on Visual Studio 2012, it's giving me the same result as Visual Studio 2013.
Is this call stack enhancement also available for C++ (no C++/CX) Win32 console application?
Yes, this is available for Win32 console applications as long as your are using a Tasks implementation.
I'm not sure what's going on. I've attached the managed sample to the post so that you can verify whether you are really seeing the same exact call stack between the two.
There are some cases where the CLR will optimize async calls into synchronous ones, so this may be what you are seeing.
I had first-chance exception more easily. I was using onSelectionChanged event to populate data for use with ListBox when onTapped would occur, but the onTapped handler failed at times to find data.