New Breakpoint Configuration Experience in Visual Studio 2015
October 6, 2014
If you use Visual Studio to develop code, the chances are good that you set breakpoints on a regular basis as part of debugging. You may however not be aware that breakpoints can be configured with conditions and actions to improve your debugging productivity. In Visual Studio 2015 we’re pleased to introduce an improved experience that makes configuring breakpoints significantly easier to find and use for breakpoints associated with a specific line of source code:
- Conditional statements break only when conditions you specify are met. Think of this as adding an “if” statement to your code and placing the breakpoint inside the “if” statement so it is only hit when the conditions you entered are true.
- Hit counts break only after the breakpoint has been hit a certain number of times. These are useful in situations where code is called multiple times, and you either know the exactly when it is failing, or have a general idea that “it fails after at least” a certain number of times.
- Filters break when the breakpoint is hit on a specific thread, process, or machine and are useful for debugging code running in parallel.
- Tracepoints print a message to the output window and are capable of automatically resuming execution. These are useful for doing temporary logging when you need to trace something and don’t want to have to break and manually track values.
In this post I’ll show you how to create and configure breakpoints with the new experience. Then we’ll walk through debugging several problems using each type of configured breakpoint along the way.
Updated Experience
The first thing you will notice when you set a breakpoint is a small toolbar appears next to the breakpoint glyph (the red circle in the left margin) that has two options, settings, and an enable/disable breakpoint toggle.
If you prefer to access the settings from the context menu, we have consolidated the options for accessing the various settings to simply have “Condtions…” and “Actions…” for entry from the glyph itself and to have “Settings…” from the Breakpoints window (if you’ve used these in previous releases of Visual Studio you will remember there was a separate menu option for each type of breakpoint).
When you select “Settings…” for the breakpoint a non-modal Peek window appears in the editor where you can configure all possible settings for the breakpoint. You should think about the possible settings for a breakpoint as falling into two categories:
- Conditions: control when the breakpoint is hit, by default a source breakpoint implicitly has the condition of “when execution reaches this location”
- Actions: control what happens when all of the breakpoints conditions are satisfied. The default implicit action is “break”
You can see below that the updated UI reflects this way of thinking about breakpoints.
Since this is a Peek window, it is non-modal and inserted between the lines of code (it is between line 87 and line 88 above, it does not cover any source). This means that I can continue typing, copy and paste from the editor into the dialog, etc. To dismiss it click on the “Close” button. Note that all changes are saved automatically, there is no cancel button.
Tip: You can use the context menu options of “Conditions…” and “Actions…” as a shortcut to open the peek window with the respective checkbox already checked so focus is in the edit box ready for input.
To see configuring conditions and actions, continue reading…
Walkthrough
The example app we are going to use has Web API services that are consumed by rich client applications. I’ve been asked to create an encoding library so communication between the two is no longer passed in plain text. You can follow along with the post by downloading the attached sample that uses a shift cipher. Note: For the purposes of keeping the sample as simple as possible I’ve placed all the logic into a console application, normally I would place the tests in a separate unit test project.
I’ve written the basic logic, and validated that encoding and decoding “Hello World” works as expected. Unfortunately, my next test that checks every ASCII character is failing on character 75.
Hit counts
To debug this I set a breakpoint in the applyByteShift function (in CustomEncoder.cs, line 84) where I’m doing the byte shift during encoding. Since I know it’s failing on the 75th character I want the debugger to break only when applyByteShift is called by that iteration of the test loop testing. I could use a conditional statement when the byte passed in is 75, but I can’t be sure that isn’t part of the problem. Instead, I will set a hit count breakpoint to break the 76th time this function is called (it’s a 0 based loop, so character 75 is passed from the 75 + 1 iteration of the loop) since that will guarantee I break in the failing code path. I open the settings window for the breakpoint, and check the “Conditions” checkbox. I see a grid that is waiting for me to enter a conditional expression.
Since I’m going to use a hit count instead, I click the dropdown and choose “Hit Count”
I enter ‘76’ and press Enter. Note, once I’ve specified a valid value, the change will be automatically committed as soon as focus leaves the control whether I press Enter, click outside it, start debugging, or close it.
I can also change the comparison operator on the Hit Count to choose between equals, is a multiple of, and greater than or equal to.
To edit the value again, I just need to select the specified value (e.g. by clicking on it) and it will return to an editable state.
At this point I could choose to add another condition if, for example, I wanted to use hit count in combination with a conditional expression or filter. I don’t need that at the moment however so I’ll start debugging and because the Peek window is non-modal I don’t even have to close it! Reminder: changes are automatically saved, there is no cancel after you make an edit.
When the breakpoint is hit, notice that I can see the current hit count in the Peek window, and have the option to reset it.
Note: you can see the current hit count for a hit count breakpoint the breakpoint’s tooltip
…and the hit count for any breakpoint (regardless of whether it has a hit count condition specified) is shown in the breakpoints window while in debug mode.
Once my breakpoint is hit, looking at the data values I can see the bug is that after the byte shift, character 75 becomes 128 which is not a valid ASCII character.
TIP: You can pin a DataTip to the editor as shown in the screenshot above
To fix this issue, I will use modular arithmetic in both applying and removing the byte shift (so 128 will become 1 which is valid).
Running it again the test for every character now passes
It’s time to move on to testing this when calling my Web API methods.
Conditional statements
The application I’m testing against keeps track of the projects my team has created or collected over the years. I’m going to start by retrieving applications from an API that accepts the desired application type (e.g. Mobile, Desktop, or Web). The goal is to encode the parameter before it is passed, and then decode it on the service side returning matching applications. Running my tests shows that it succeeds for two out of the three types I’m attempting to retrieve.
I suspect that it isn’t being decoded correctly on the remote side so I want to debug through that code path, but only for the failing case. Meaning I want the debugger to stop when the parameter passed is “Desktop” but not when it’s “Mobile” or “Web”, which is the job of a conditional breakpoint. However, since I suspect the problem is that “Desktop” isn’t being decoded correctly I can’t use that as my condition, instead I will set my conditional statement to break whenever the decoded value is not “Mobile” or “Web”.
It is worth noting that conditional expressions can be as complex or as simple as you need. Any expression that evaluates to a Boolean value in the language your application is written in is valid input.
Now that my breakpoint is set, I configure my solution to start both the web project and console application, and start debugging. The debugger breaks and I can see that for some reason the word “Desktop” is decoded to “Deskto”
Actions
In order to figure out why the word “Desktop” isn’t being coded correctly, I want to record exactly what each character is encoded to on the client side, and then see the corresponding decoding for the same characters on the server side. I don’t want to have to break for each character and manually record it somewhere, so I’m going to add an action for the debugger to log the characters to the Output window as they are encoded and decoded.
To do this, I set a breakpoint on the function that applies the byte shift, and click the “Actions” checkbox to add an action to Log a message (called a tracepoint). Also, a second checkbox “Continue execution” appears and is checked by default. When checked, the breakpoint will automatically resume execution of your program after printing the message. If you want the breakpoint to print a message and also stop until you manually resume execution, uncheck this box.
Additionally, note that the debugger offers information that can be printed by referencing pseudo-variables denoted by a $. In Visual Studio 2015, we’ve added IntelliSense for the available pseudo-variables.
To debug my current problem I don’t need any of the pseudo-variables, so I’ll change the message to show what the original byte code is, and what it is changed to. Note, that to print values from variables in the application, the variable name needs to be placed inside curly braces (expressions are subject to the same limitations as the watch window, if it cannot be evaluated in the Watch window it cannot be evaluated in a tracepoint). Anything that is not inside of curly braces will be printed as typed. For example “Hello world” will appear as “Hello world” in the output window, where “Hello {world}” will appear as “Hello <value of variable world>”.
Combining Conditions and Actions
Next, I’ll move to the function where the byte shift is removed, and add a tracepoint to capture what is happening when the byte shift is removed. However, since I have other tests running that are decoding strings there is the potential for a lot of extra noise in the Output window. To reduce this noise I am going to set this tracepoint to only print when it is hit in the server process, meaning it won’t print anything when this code path is executed in the console application running the tests. A breakpoint conditioned on the process, thread or machine is called a filter breakpoint.
Since I’m running the server code in iisexpress, am going to add a Filter condition of ‘ProcessName == “iisexpress.exe”. Notice that IntelliSense is now available for the filter properties in Visual Studio 2015.
When I run this, I see that the last character is being dropped from the string (char 38 is never decoded).
A look at ASCII character 38 show it is an ‘&’ which is a special character when used in URLs. So it is being dropped from the string passed via the URL. To fix this and any other potential problems with special characters, I tweak the code to convert the encoded bytes to a base 64 string instead of ASCII.
After this change all of my tests are now passing.
Changing settings from the Breakpoints window
Breakpoint settings can also be accessed by right-clicking a breakpoint in the Breakpoints window (accessed from the menu by Debug -> Windows -> Breakpoints) and choosing “Settings…”.
When the settings are opened from the Breakpoints window, the settings UI will be the same that was seen in the Peek window, but it will appear in a dialog box, rather than changing the editor to that source location and opening a Peek window (if instead you wanted to navigate to source for that breakpoint just double click on the breakpoint).
In Conclusion
In this post we walked through an example of configuring each possible setting for a breakpoint in the new breakpoints experience. While we didn’t combine the options in all possible ways, hopefully you can see how you can configure breakpoints to debug issues more efficiently. Feel free to download the attached sample and try it yourself, and read our previous posts covering each breakpoint type in more detail.
If you have any questions or feedback on our new experience or breakpoints in general I’d love to hear them below, through the Send a Smile feature in Visual Studio, or in our MSDN forum.
















Looks great!
Will the new breakpoint window also be extendible (via mef for example) if i, say wanted to add my own actions of conditions? that'd be neat 🙂
I'm surprised you chose to rework the breakpoint settings dialogs, I didn't see any issue with the way it was before. The inline Peek window is probably slightly more comfortable, on the other hand the same settings in a window look weird now.
I've known conditional breakpoints for a long time but have never found them to be particularly useful, mostly because inserting an if (…) Debugger.Break() takes hardly any longer and, more importantly, does not have any impact on performance. In many cases when I tried to use conditional breakpoints in the past they took an awful lot of time to process and the fact that it's often in some tight loop that I want to place the breakpoint (e.g. to break into a specific iteration of an algorithm) makes them impractical for me.
Can you add & manipulate the conditions and other things without your hands leaving the keyboard?
My current solution to debugging is to have the typical debugger conditions and other stuff more easily available in my own class. Instead of having to hunt and click around some dialogs with mouse or clutter the code with long method names that don't stand out in the code, I just have a single letter class (g for global) and put shortened named in all-capital there. I have some code there to toggle them on/off for release build.
Now, Ideally, I could specify that my debug class is in a "debug class project" that if de-activated (unload or whatever), the calls would get somehow "grayed out" in the actual code. In essence acting as real breakpoints would except that instead of clicking them in, they're written into the actual code but the IDE somehow figures that since they're residing in the custom debug class, they would become visible in the IDE and removable or toggleable etc just like "native" VS breakpoints, except they're ones I wrote in my custom class.
What I described above is a variation of my earlier suggestion:
visualstudio.uservoice.com/…/5735299-debug-time-user-defined-assembly-import-injection
The only problems with my current system is
1) the in-code-breakpoints/debug functions aren't color highlighted (would be neat if I could have some way to tag a class in a project and calls to the methods in the tagged class would have custom color)
2) can't toggle the breakpoints one by one – a possible solution is to create a new method like: to toggle g.BRKonce() I could change that to eg. dg.BRKonce() and then have the dg class tagged and calls highlighted with another color to signify that that class contains the NOP versions of the g. class custom debug functions.
Have you changed the underlying implementation of those breakpoint settings compared to previous versions? The problem with those have always been the perf hit that they impose on the running program. Adding a simple condition can slow down execution by 100-1000 times. In my experience this never has been usable.
In the past we've always been using code such as this instead:
#ifdef SOME_DEFINE
unsigned long BreakOnID = 0;
#endif
void SomeFuncCalledOften()
{
#ifdef SOME_DEFINE
if (breakOnID != 0)
DebugBreak;
#endif
}
Now if your new tech is able to let me add some breakpoint without any perf hit, I'll be happy… Otherwise this is just some more useless crap in visual studio.
These updates look interesting, however I have two questions/comments here.
– Does the conditional statement editor still not offer smart completion or Intellisense? The coloration in your example was all wrong so I'm assuming this is the case. Why not use the new Roslyn services here for proper editor support?
– It seems like a natural extension here would be to save "breakpoint profiles", eg. save the location of breakpoints within a given set of files for re-use later or by someone else.
I've been fairly satisfied with the existing breakpoint experience, but this is still a welcome change. My only problem is cosmetic: the new settings form needs a second look from a visual design perspective. Expression syntax coloring would also be nice.
While we're on the topic of breakpoints, I've been debugging binaries without symbol information lately and it would be nice if VS would keep assembly-level breakpoints enabled between debugging sessions (relocating them to account for ASLR as needed). It is annoying to have to manually re-enable them each time the process is started.
@aL: Extensibility is not something that is currently planned for Visual Studio “14”, however is something we can consider for future releases. I would recommend creating a suggestion on User Voice visualstudio.uservoice.com. You should be able to achieve some conditions currently by writing a method in your application that returns a bool and then providing that as the conditional expression.
@Chris and @JSP: Thank you for the feedback on performance. This CTP does not contain any changes to the performance of conditional breakpoints (using conditional expressions). It is however something we are aware is a problem and is on our radar to improve.
@drd: The feature is designed to allow you to open the peek dialog, navigate the settings, and close it all without your hands leaving the keyboard. There however are some bugs in this CTP version that will affect that. We are aware of these and they will be fixed before the final version of Visual Studio “14”.
@MgSm88: Regarding your question about IntelliSense, what language do you typically develop in? The debugger supports IntelliSense if the language service implements it correctly. Since you mention Roslyn, are you doing C# or VB? If so, yes these support IntelliSense just like the editor (but no syntax highlighting). Regarding your second question about breakpoint profiles have you seen that Visual Studio has the ability to import and export breakpoints (msdn.microsoft.com/…/dd293657(v=vs.100).aspx) this can be combined with breakpoint labels (msdn.microsoft.com/…/dd293674(v=vs.100).aspx) to let you import and export select sets.
@Tristan: Thank you for the suggestions, would you please create suggestions on User Voice (visualstudio.uservoice.com)?
Is it still impossible to set data breakpoints when debugging an application with mixed managed and native code?
Well, this is quite amazing, one of the good reasons to use an IDE over plain text editors. Having said that, of all debugging sessions I do (ASP.NET web developer) I need features like conditional or hit count less than 0.1% of the time.
@Morten: Setting data breakpoints in native code while mixed debugging works. .NET does still not support data breakpoints, you can vote for this on UserVoice at visualstudio.uservoice.com/…/6097301-support-data-breakpoints-for-c
Great post!
While that uservoice data bkpt request specifically calls out C#, what I really need is data breakpoints for C++/CLI code. ie. the Mixed Mode debugging @morten mentions
@fourbadcats, thank you for the clarification. The limitation as I mentioned is with the underlying runtime (CLR) that is running managed code. So whether the language you are writing in is C#, VB, or C++ compiled with the /clr switch it's all running on the CLR. If the CLR were to support data breakpoints we would be able to support them for any language running on the CLR.
Why is the logging called action when there is only a single action to perform? Can I write my own actions to be triggered? Will more be added later?
@Justin, Enabling more "Actions" is one of our long term goals, so it made sense for us to design the UI with that in mind, even though right now all you can do is "Log a Message".
As per Andrew B Hall's comment from above, user extensibility is not something that is currently planned. I would recommend creating a suggestion on User Voice visualstudio.uservoice.com if that is something you are interested in.
Hi,
I'm not abble to set a conditional breakpoint in C++ source code, same thing for hit count, I've got the following messages :
C++ does not support breakpoint conditions
C++ does not support breakpoint hit counts
Filter is working well
Is it a limitation of conditional breakpoint ?
@Copain, conditional breakpoints and hit count breakpoints should both work for C++. Are you using Visual Studio 2015 RTM? It sounds like there may be something wrong with your installation please try to repair it, and also double check you have the C++ components installed.
Hi Andrew,
Excellent ! Yes it was due do bad installation of C++ components !
Thanks fort your help
I have installed VS2015 Professional edition and I also got the "C++ does not support breakpoint conditions" error.
I fixed it by Modifying the install and selecting “Common Tools for Visual C++ 2015.”
Repairing the install did not fix the problem.
@Mike
Thanks for the feedback. There is a bug that conditional and function breakpoints will not work for C++ if the C++ components are installed. We will be fixing this in a future update, but for now the only workaround is to install the C++ components.
The "Current" hit count begins to increment when the breakpoint condition is selected to be "Hit Count". Thus to setup a break at the Nth execution either the breakpoint must have been entered as a "hit count", or the breakpoint must be changed to a "hit count" with a re-run required. Only after the re-run can N be discovered.
The re-run step could be avoided if the hit count was always incremented, and the gui improved if the count were made a symbol available in the conditional. Thus a break on the Nth execution would look like "Conditions: $hit_count > 27", where "$hit_count" is the internal symbol associated with the break.
Data break's would not increment their counters because they are implemented by Intel's processor and by themselves do not incur an execution time hit as JSP gripes about.
@BobConsultant2
Thanks for your suggestion here about how to further improve Breakpoint Settings in the future. To summarize your suggestion, it sounds like what you are wanting is to keep the current hit count associated with the breakpoint and build on top of it during the same debug session, as opposed to what currently happens where the hit count resets back to zero when you set a new hit count condition. Thanks again for your feedback, and we will keep this in mind when considering additional improvements to this feature.
It doesn't add any new functionality so given the fact it doesn't resize properly, my experience is much worse now.
@john — Thanks for leaving a comment. Can you please tell me more about what you mean by "it doesn't resize properly"? Are you changing the width of your editor and are having difficulty entering text in the edit fields? How do you expect it to resize?
Why does the conditional statement editor in VS2015 not offer Intellisense in VB.NET? Whereas in C# Intellisense is provided, in VB.NET it is not.
Microsoft Visual Studio Professional 2015
Version 14.0.24720.00 Update 1
Microsoft .NET Framework
Version 4.6.01055
Visual Basic 2015 00322-40000-00000-AA465
Visual C# 2015 00322-40000-00000-AA465
@Urs — IntelliSense for VB is offered in the edit box for conditional expressions, just like for C#. We are using the same IntelliSense that is provided by the editor in these cases. I was unable to reproduce the behavior you are seeing on the same version of Visual Studio 2015 Update 1. Are you getting IntelliSense in the editor for VB, and not in the Conditional Expression edit box? Does this reproduce for you on a simple VB console Application as well?
@Kaycee — Same behaviour on a new VB.NET Console App Project: Intellisense in Code works fine, but not in the edit box for the conditional expression. But I noticed that when I disable JetBrains ReSharper (9.2), Intellisense also works in the conditional expression edit box.
@Urs.Muntwyler – Thanks for following up. This is a known issue with using ReSharper (9.2) and we reached out to JetBrains to communicate the problem. They think they have fixed this bug with ReSharper 10, but they created an issue in their tracking system to verify it gets fixed. Here is the link their representative sent to us that we wanted to share with you. youtrack.jetbrains.com/…/RSRP-452799