How to Debug Sitecore Kernel in Visual Studio using Reflector Pro or dotPeek

A post from Georgi Bilyukov a couple of months ago about Debugging Sitecore Using DotPeek informed me of a new feature in the latest version of JetBrains dotPeek that allows it to function as a symbol as a symbol server. If you haven’t read the post then I suggest you have a quick read.

So this sounded great – a way to debug Sitecore code, see where those calls end up and what is going on in the internals.

I’ve been using dotPeek for a while now, and before that .NET Reflector. These tools have been invaluable in getting a peek at the Sitecore code, and has become an everyday tool alongside Visual Studio and Resharper. My usual way of trying to debugging something Sitecore related is:

  • trial and error
  • copying the code for an existing pipeline and adding it before the default Sitecore one
  • override Sitecore controls, changing the codebeside to point to my own Class (which is also a copy of the Sitecore one)
  • grepWin the /sitecore folder
  • use dotPeek to generate a Visual Studio project and then grepWin the files to try and find something related as a starting point

So something that is very quick to debug in your own code can become quite long winded. Using dotPeek as a Symbol Server sounded hopeful, but anyone that has used Redgate .NET Reflector Pro will know that this is nothing new, just it is now free 🙂 For those of you that do not know, the Pro version is a Visual Studio plugin that allows you to debug 3rd party libraries, decompiling and set break points without leaving the IDE. I’ve used the plugin before, over 3 years ago, but never continued past the trial period for one main reason. Alas, using dotPeek I was faced with the same issue.

Debug Sitecore - Value Optimized Away

Same issue in the Immediate window:

args
Cannot obtain value of local or argument 'args' as it is not available at this instruction pointer, possibly because it has been optimized away.

Stepping through code

Sometimes you just want to step through code and see where something ends up. For that purpose, this worked fine. But we are not able to see the values of the local variables, which is quite annoying 😦

Another problem with debugging compiled assemblies is optimized assemblies. For optimized assemblies, some debugger functions are just not available, e.g. you would not see values of local variables, even if symbol files are correct. You can check if the assembly is optimized when Visual Studio is in the debug mode – open the Modules window (Debug | Windows | Modules) and check the Optimized column.

I know some will argue that we should not really care what goes on in those external libraries and we should treat them as black boxes, but as any Sitecore developer worth their salt knows, it’s not that black & white, we very often have to act on variables and arguments passed into Sitecore code. So it’s back to duplicating code or replacing controls to see those values.

But not just Sitecore. Any third party library. I’ve been using Glass Mapper in projects for a while now, which we add in using NuGet. Yes, the source code is available on GitHub which we could download and add into our solution (and I’m sure there is an even more clever way debugging this) but there is a reason it was added in as a NuGet package in the first place.

Last week I was debugging some code which appeared like it should work but it was acting very differently to what I was expecting, even though I had duplicated a standard Sitecore Pipeline. I knew the limitation of dotPeek Symbol Server since I tried it a few months ago, so decided to take that old friend Reflector Pro for a spin again, so I installed the trial version. And after some research it appears there is a way to debug 3rd party libraries AND see the local variables!

Disable optimizations during debugging

There are 2 steps required. Firstly you need to start VS with the Environment Variable COMPLUS_ZapDisable=1. Create a .cmd in any text editor with the following:

set COMPLUS_ZapDisable=1
cd /d C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE
start devenv.exe
exit

You also need to disable JIT optimizations while debugging. Create an .ini file with the following and call it Sitecore.Kernel.ini (and Sitecore.Client.ini etc) and place it in the /bin folder alongside the DLL.

[.NET Framework Debugging Control] 
GenerateTrackingInfo=1 
AllowOptimize=0

Then follow the instructions to create the pdb and add Reflector or dotPeek as a Symbol Server location in Visual Studio. Make sure you have also unchecked “Enable Just My Code” from the Debug Options.

The last point is to make sure you start Visual Studio with Administrator privileges in order to be able to attach to the w3wp worker process in order to debug:

Debug Sitecore - Open CMD as Administrator

And voila! We can now step through Sitecore code, set breakpoints AND see local variables! 🙂

Debug Sitecore - Inspect Locals

Debug Sitecore - Inspect Parameters

This should work for any 3rd party library for which you do not have the source code, not just Sitecore.

Setting Breakpoints

Depending on what you are using, there are different ways to set breakpoints in order to debug the 3rd party library.

If you are just using vanilla Visual Studio and dotPeek Symbol Server then you will need to:

  • Click Debug > New Breakpoint > Break at Function > enter the full name of the function

If you use Resharper then you can set you can use the Assembly explorer to browse and assembly, open the code in VS and set the breakpoint:

  • Resharper > Windows > Assembly Explorer

If you are using Reflector then a similar assembly explorer is available making it very simple to set your breakpoints.

  • .NET Reflector > .NET Reflector Object Browser
Set Break points directly from Visual Studio

Set Break points directly from Visual Studio

Resharper Assembly Explorer

Resharper Assembly Explorer

.NET Reflector Object Browser

.NET Reflector Object Browser

Debugging using JetBrains dotPeek vs Redgate .NET Reflector Pro

The above methods worked using both dotPeek Symbol Server and .Net Reflector Pro.

Both seem to achieve the same results, but my experience with Reflector Pro was much better. When attaching to w3wp process Visual Studio take approx 2-3 minutes to load the assemblies. This seems much slicker in Reflector. Also using dotPeek it was a less satisfactory debugging experience – sometimes I was able to see the local variables, next time I started Visual Studio it would complain they had been optimized away. I tried many times, in different combinations (restart IIS, restart Symbol Server, start applications in particular order etc) but couldn’t find any consistency to when it would work. It always seemed to work with Reflector Pro.

So I think I’ll head back to Reflector Pro. Well worth the £125 in my opinion, but you know, feel free to reach out and shout me a free copy 😀

I’ll also throw in a plug for JetBrain’s Resharper as well, it’s an awesome tool and once you’ve used it for a while you’ll have trouble using vanilla Visual Studio again. Also feel free to throw me a free copy, time to upgrade it anyway 😀

Both add in the functionality to jump to definition by pressing F12 in Visual Studio, you it’s much easier to hop around that external library from within the IDE and calls in your own code.

EDIT
The issue I was having with dotPeek Symbol Server may be due to IIS loading a precompiled version of the assemblies before the debugger is attached. This article about Debugging into SharePoint and seeing the locals points to a registry setting to prevent that

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
Add Key: COMPLUS_ZAPDISABLE
Type: REG_SZ (String)
Value: 1

I’ll give this a try and update the post if anything changes.

Further EDIT:

Be sure to read the comments below, there are some very useful tips.

From Chris – this works perfectly for me:

I also found another way by accident: If you have your debugger attached and then modify the web.config.
After sitecore has restarted (still having the debugger attached) you’ll have access to the local variables

Also see PowerShell script from Anton to build the .ini files:

Get-ChildItem (Get-Item -Path ".\" -Verbose).FullName -Filter *.dll |
  Foreach-Object{
    $newName = $_.DirectoryName +"\"+ [System.IO.Path]::GetFileNameWithoutExtension($_) + ".ini"
      "[.NET Framework Debugging Control]
      GenerateTrackingInfo=1
      AllowOptimize=0” | Out-File $newName"
    Write-host $newName
  }

Additional Reading:

17 comments

  1. Ola Owolawi · January 12, 2015

    Nice one

  2. Chris van de Steeg (@csteeg) · June 18, 2015

    Great tip!
    I also found another way by accident: If you have your debugger attached and then modify the web.config.
    After sitecore has restarted (still having the debugger attached) you’ll have access to the local variables 🙂

  3. KevinKevin · July 8, 2015

    Nice post. Did you find a solution for this “sometimes it works, sometimes not” with dotPeek? I experience similar issues. It worked this morning, now in the afternoon it doesn’t 😦

    • jammykam · July 8, 2015

      You could try setting COMPLUS_ZAPDISABLE in the registry, I can’t recall getting round to trying that since my laptop died on me at the time.

      Failing that, could you try modifying the web.config whilst the debugger is attached like Chris suggested?

      • KevinKevin · July 8, 2015

        The registry didn’t help. But the trick with the web.config really did. Great 🙂 What a hack 😉

      • jammykam · July 8, 2015

        Great! My machine is so out of wack that I couldn’t try it… but the issue is exactly attaching to the worker process before the CLR has a chance to load an optimized assemblies. Happy debugging! 🙂

  4. Dan Solovay (@DanSolovay) · September 8, 2015

    Great post. I had to do one additional step to get this working. I had to uncheck “Enable the Visual Studio Hosting Process” on the Project properties Debug tab for the project that calls that references the Sitecore.Kernel. (Credit to http://www.cplotts.com/2009/01/07/disabling-optimizations-when-debugging-net-framework-source-code/).

  5. chaturangar · September 9, 2015

    Great post. will help a lot 🙂

  6. w. paap · October 20, 2015

    Great post, thank you! Just recently found this, I did not know it could be done with dotPeek. I tried it with VS2015 and if you enable the symbol server it works just fine without having to set any registry values and stuff. I recommend when you enable the Symbols in VS you set the ‘Only specified modules’, this way it will load a lot faster. Same thing in dotPeek, set it to ‘Assemblies opened in the Assembly explorer’.

  7. Pingback: Disabling optimizations – debugging third-party dlls with Reflector Pro | Paul George
  8. Sean Holmesby (@seanholmesby) · March 23, 2016

    Great post!
    Just wondering about the format of the function breakpoint you mention (yeah I know this is a general Visual Studio question, but I can’t find the answer anywhere).

    You say:-
    ‘If you are just using vanilla Visual Studio and dotPeek Symbol Server then you will need to:
    Click Debug > New Breakpoint > Break at Function > enter the full name of the function’

    Can you tell me what the format is that’s required here?
    I tried all sorts of things (fully qualified, not qualified, exact method signature etc.) and couldn’t get it.

    Any ideas?

    Thanks

    • jammykam · March 23, 2016

      I can’t recall unfortunately… I will try looking for you tomorrow if you are still stuck, but try using the following. I have Resharper so just used that method…

      `Sitecore.Pipelines.Attach.CheckSize.Process`
      or `Sitecore.Pipelines.Attach.CheckSize.Process(Sitecore.Pipelines.Attach.AttachArgs)`
      or `Sitecore.Pipelines.Attach.CheckSize.Process, Sitecore.Kernel`

      • Sean Holmesby (@seanholmesby) · February 6, 2018

        I finally got around to using this again.
        I had mixed results. First time I needed the syntax stating the attribute:-
        `Sitecore.Pipelines.HttpRequest.CheckIgnoreFlag.Process(Sitecore.Pipelines.PreprocessRequest.PreprocessRequestArgs)`
        But maybe that was because this particular Process method is overloaded (two different signatures).

        Once I managed to set a breakpoint for the DLL once… it seemed like I didn’t need the argument included after that.
        So `Sitecore.Pipelines.HttpRequest.CheckIgnoreFlag.Process’ would then work, and set breakpoints on BOTH methods.

  9. anton tishchenko · June 27, 2016

    Powershell script to build .ini files for your assemblies(In most cases you need much more Sitecore assemblies to debug, not only Kernel and Client):
    Get-ChildItem (Get-Item -Path “.\” -Verbose).FullName -Filter *.dll |
    Foreach-Object{
    $newName = $_.DirectoryName +”\”+ [System.IO.Path]::GetFileNameWithoutExtension($_) + “.ini”
    “[.NET Framework Debugging Control]
    GenerateTrackingInfo=1
    AllowOptimize=0” | Out-File $newName
    Write-host $newName
    }

    Also, do you figure out how to use this approach when Sitecore site is not started from VS, but is attached w3wp process? IIS puts and uses assemblies from \Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\ . And it is not convenient to put ini files there.

    • jammykam · June 27, 2016

      Hi Anton,

      I always attach to W3P process since I work outside of web root. This should work work fine, but be sure to recycle your app pool by making a small change to web.config whilst the debugger is attached.

  10. Pingback: Debugging Sitecore – optimized away – Coresighted
  11. Peter Nazarov · November 18, 2017

    Re: “You also need to disable JIT optimizations while debugging. Create an .ini file with the following and call it Sitecore.Kernel.ini (and Sitecore.Client.ini etc) and place it in the /bin folder alongside the DLL.”

    It did not work unless I placed the .ini file next to the DLL in “C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\193e5af4\2cdad63a\assembly\dl3\39be919e\0068b684_edefd201\” where the actual DLL is executed from
    – you can observe the execution location next to the DLL entry in Visual Studios Modules window (Debug | Windows | Modules).

Leave a comment