DevForce® Classic Tech Tips
DebuggingNonUserCode 



DebuggingNonUserCode Level 200
DevForce Express
Mar 21, 2007

Visual Studio 2005 has some exceptional debugging capabilities, but every so often we encounter a situation where we get some very non-intuitive debugging behaviors. Among the more annoying of these is when we are running our code in the debugger and it breaks at some strange location in some third-party vendor’s code. We know that this is not our code so our first assumption is that we have somehow abused the
third-party’s API. or that the third party has some bug in their code.

Occasionally, neither of these is true. Sometimes in these cases after encountering the exception we tell the debugger to continue, without changing anything, and the code continues to run and behaves exactly as intended. This same code also runs without a problem in release mode. So, why the exception? Is there some hidden problem in the calling code, or in the third-party library?

This condition is usually caused by the combination of code generators or sample code that is embedded into an application along with the generated code’s assumption that any exception that it throws will be handled properly further up the stack.

Within IdeaBlade we encounter this situation within our auto-generated property setter code. The example below is a simplified version of IdeaBlade property setter code. Inside this auto-generated setter logic, IdeaBlade performs a number of business validation checks and will throw a specific exception if any of these checks fail. Ideally we want this code to break at the location where the LastName setter was called. Unfortunately, the code as shown below will instead break inside of the setter.

 

C#:

public virtual System.String LastName {
  get { . . . }

  set {
    // SetValue throws a Validation exception if the
    // “value” provided does not meet prespecified
    // business rules.
    SetValue(“LastName”, value);
  }
}


VB.NET:

Public Overridable Property LastName() As System.String
  Get
      ...
  End Get

  Set

    ' SetValue throws a Validation exception if the
    ' “value” provided does not meet prespecified
    ' business rules.
    SetValue(“LastName”, Value)
  End Set
End Property

From the standpoint of the developer debugging this application, this is fairly non-intuitive. I want to know where the code that I wrote broke, not where the auto-generated code failed. This is a fairly simple case but in the real world the stack is often much deeper and consequently even harder to get a handle on.

The fix is fairly simple. The code below causes the debugger to break on the line that called the LastName setter unless that code is itself inside of a try catch block. What is interesting is that these two code samples cause very different behaviors when run inside the debugger, but identical behavior when run outside of it.

 

C#:

[System.Diagnostics.DebuggerNonUserCode]
public virtual System.String LastName {
  get { . . . }

  set {
    // SetValue throws a Validation exception if the
    // “value” provided does not meet prespecified
    // business rules.
    SetValue(“LastName”, value);
  }
}

 

VB.NET:

<System.Diagnostics.DebuggerNonUserCode> _
Public Overridable Property LastName() As System.String
  Get
      . . .
  End Get

  Set
    ' SetValue throws a Validation exception if the
    '“value” provided does not meet prespecified
    ' business rules.
    SetValue(“LastName”, Value)
  End Set
End Property

It turns out that, in practice, code like that shown above is often executed in the context of a WinForms application where the LastName property is bound to some control via .NET databinding. In this case, .NET databinding is built with the expectation that errors such as this may be thrown inside of a property setter and it that the databinding infrastructure will handle the exception. This means that we really do not want the debugger to break on the exception. We want the .NET databinding apparatus to handle this exception so that we in turn can use the databinding mechanisms to provide an error bullet or some other UI manifestation of the error.

So why is any of this important to non-framework developers?

The reason is that the case described above is not limited to third-party framework code. In fact we often find within large applications the need to have lower levels in the application stack throw errors that we “expect” to catch and handle further up the stack. Each of these is a candidate for the DebuggerNonUserCodeAttribute.

So what if we want the best of both worlds? What if we sometimes want to debug this at the lowest possible level and sometimes we want to debug at a higher “intent” level?

Visual Studio provides a toggle to do exactly this. Inside of the Tools – Options – Debugging window there is a checkbox next to the option “Enable Just My Code”. By default, this is checked and the debugger will behave as described above. However, by unchecking this option, we in effect remove the effect of the DebuggerNonUserCodeAttribute and revert back to our original behavior.

There is also a DebuggerHiddenAttribute which hides the code from the debugger, even if “Enable Just My Code” is turned off. This is intended for those cases where we never want to let the developer debug into the specified method or property at all. In effect, this constitutes a more absolute version of the DebuggerNonUserCodeAttribute.