The other day we encountered a problem with some inconsistent processing within the POP adapter for BizTalk. If the adapter was processing an email with a very specific set of attachments, the adapter failed to hand the message out to the BizTalk engine, and all following messages on the receive adapter became blocked. Anecdotally we believed this was related to the S/MIME decoder being used by the adapter, but we were struggling with what specific characteristics of the attachments required to reproduce the issue.
Let me make this clear from the start … we didn’t actually manage to resolve this issue using this technique. Having said that I did find the whole process of debugging IL for runtime code very interesting and wanted to share the basics for getting started.
Step 1: Install the components
The tools we used for this are both available for free download. These will need to be copied onto the machine where the .NET process you wish to debug is located.
- Reflector (http://reflector.red-gate.com/Download.aspx)
- Reflector Add-in “Deblector” (http://deblector.codeplex.com/)
Installing reflector is just a matter of extracting the runtime files onto your machine. The Add-in can be installed by extracting the files to a subdirectory under the Reflector application path, then adding the Add-in into Reflector (Menu -> View -> Add-in’s).
Deblector can then be activated within Reflector from the Tools menu.
Step 2: Attach to the BizTalk process
The next step is to load the required assemblies into Reflector. In my case this was the Microsoft.BizTalk.Pipeline.Components.dll file that comes with BizTalk Server 2006.
Note that at this stage it pays to navigate through the methods you are likely to be debugging, to ensure that all the dependant assemblies are also included. Reflector will prompt you to load any decencies that are identified for the methods you are reading. This is also a good chance to learn a bit about how the application hangs together, and where logical debugging breakpoints should be applied.
Once the assemblies have been loaded we need to attach Deblector to the process to be debugged. In my case this was the BTSNTSvc.exe process.
Note: For BizTalk this got a bit complicated as there are a number of instances of this process running, so some trial and error was required to find the right one. I also found that stopping all the host instances in BizTalk Administration Console except for the one containing the pipeline you wish to debug was helpful to help filter the list.
Note that the debugger is automatically in pause mode when you attach to the process.
Step 3: Set your breakpoints, and Debug!
Using the explorer included in Reflector, navigate to the method to be debugged (in my case, MIME_SMIME_Decoder.Execute2).
Examine the IL view, and identify a line that you recognise. Reading IL can be a bit daunting, and I’m definitely not proficient with this as a language. I’ve found that searching for strings used for writing log files
Setting up the breakpoint had me a bit confused to begin with, as I could see the breakpoint button but it was not obvious as to how to select the line to apply the breakpoint to. In the end it’s as simple as selecting the line in the IL View tab and clicking the breakpoint icon. Alternatively you can use the Command textbox and the break command (b [location]). I found this useful when wanting to re-setup a number of breakpoints after restarting the BizTalk process and reattaching the debugger.
At this stage you also want to consider whether you want the debugger to break if an exception is thrown. This can be toggled using one of the icons on the toolbox.
Once you have all the breakpoints setup and ready to go, click the Play icon to let the attached process continue until the next breakpoint.
Now it’s debugging as normal – except the commands being stepped through take a bit more effort to comprehend. As a final note, I did notice that the highlighted line is often indicating the instruction prior to the one being executed so if you want to step into a specific function call then you need to do so a couple of instructions before the function is called.