February 12th, 2016

Using the DebuggerNonUserCode Attribute in Visual Studio 2015

Aaron Hallberg
Partner Director of Product

You can add the DebuggerNonUserCode attribute to your application as a handy way to tell the debugger that you don’t want to debug into specific sections of code. If you haven’t used this attribute previously, this blog post gives a summary of how you can use it as part of your debugging workflow.

If you currently use this attribute, you may have noticed that we introduced a beneficial performance improvement that impacts exception behavior for DebuggerNonUserCode. You will now get an exception notification while debugging, even if the exceptions are thrown and caught entirely within marked methods. This post provides a workaround that disables the performance feature to restore suppressing these notifications for DebuggerNonUserCode.

How to Avoid Stepping Into Less Interesting Code

The DebuggerNonUserCode attribute can be used to identify classes, structures, methods, properties, and constructors that you determine debugging through would add little value. You may want to mark specific sections of code with this attribute to make the debugging process and Call Stack window display less complicated.

For example, you could use this attribute to mark code that has been generated using external tools, or to bypass stepping into methods only used for logging. You will not hit breakpoints or step into code marked with this attribute and the Call Stack window will display that code as “[External Code]”. Using this attribute has no effect on the execution of the application, just your interactions with the debugger. You can toggle off the “Just My Code” (JMC) setting to ignore the attribute without having to remove it from your code.

To see DebuggerNonUserCode in action, look at the example below where I added the attribute to the Foo() method and hit F5 to start debugging. You can see that my Breakpoint inside Foo() was not hit, and Foo() appears as [External Code] in the Call Stack window.

clip_image001

clip_image002

You could also use the DebuggerStepThrough and DebuggerHidden attributes in your code to simplify debugging. They have the same benefits of using DebuggerNonUserCode, but there are a few small differences:

  • DebuggerStepThrough can be applied to classes, structures, methods, and constructors. You will not hit breakpoints or step into code marked with this attribute, and the Call Stack will display marked code as [External Code] in the same way as the example above.
  • DebuggerHidden can be applied to indexers and properties, but cannot be applied to classes or structures. You will not hit breakpoints or step into code marked with this attribute, and the Call Stack will not display anything for marked code. It is as if it doesn’t exist in the Call Stack. In the screenshots below I changed the attribute to DebuggerHidden to show the difference in the Call Stack window.

clip_image003

clip_image004

How to Suppress Ignorable Exceptions with DebuggerNonUserCode

Sometimes when debugging you encounter and handle exceptions that are rarely of interest, like parsing an Enum. When you configure the debugger to break when exceptions are thrown, you may find yourself breaking more than desired in these instances. You can add the DebuggerNonUserCode attribute for these situations to suppress being notified of these exceptions.

However, in Visual Studio 2015 we introduced a beneficial performance improvement when debugging .NET code that impacts the DebuggerNonUserCode attribute. This performance feature significantly reduces the overhead that can happen when handled exceptions occur outside of your code, and leads to big debugging performance benefits. The debugging performance improved because when Just My Code is enabled, the debugger no longer gets notified of exceptions that are thrown and handled outside of “your code”. However, for this situation “your code” does not include the attributed code. So when you have enabled Exception Settings to break when thrown, exceptions thrown and handled within attributed code will still break. The performance improvement only impacts exception behavior so when using the attribute breakpoints will still be ignored and you will not step into attributed code while debugging.

If you happen to find yourself in a position where the ability to ignore exceptions inside methods marked with DebuggerNonUserCode is more important than the performance wins we introduced, you can revert to the old behavior by turning off the performance feature describe above. You will lose all the benefit you were receiving from the debugging performance improvement, but you will no longer break on exceptions that are thrown and caught within attributed code.

To enable this, run the following command from your command line that will tweak the registry for you:

reg add HKCUSoftwareMicrosoftVisualStudio14.0_ConfigDebuggerEngine /v AlwaysEnableExceptionCallbacksOutsideMyCode /t REG_DWORD /d 1

Note: This registry key will only work in Visual Studio 2015 Update 2 and beyond.

Wrap up

We thoroughly investigated the impact of trying to make both the performance feature work and the DebuggerNonUserCode attribute work as expected, but ultimately we were unable to arrive at a performant solution. The positive tradeoffs were significantly skewed toward enabling the performance feature by default and providing an option to turn it off for affected users of the DebuggerNonUserCode attribute. We apologize for any inconvenience this may have caused. As you continue to use the attribute to simplify your debugging experience or try it out in your code for the first time, we welcome feedback with open ears so please let me know your thoughts on using this attribute in the comments section below, through Visual Studio’s Send Feedback tool, or via Twitter.

Author

Aaron Hallberg
Partner Director of Product

Aaron has been part of the Azure DevOps team since Team Foundation Server 2008, first as a developer and now in product.

1 comment

Discussion is closed. Login to edit/delete existing comments.

  • Abuzab

    I would like to be able to suppress ignorable exceptions in Visual Studio 2019, but the debugger hack no longer works. Is there another way to accomplish this?