📜 ⬆️ ⬇️

Developer .NET Debugging Tools

From the translator: I stumbled upon this article by chance when I was looking for information on controlling the loading of characters during debugging. And although there was not much information on this issue, I read the whole article with pleasure. Most of them were known to me before, but not all. I am sure that many will find in it for themselves something useful. The article was written a year and a half ago, however, not all are switching to new versions of the studio and related tools immediately after they appear, so the article has not lost relevance.

Bugs occur at two stages of the code life cycle: during development and in production. Often, errors that come out within 10-15 minutes from the moment of writing the code, we do not even consider bugs - they are just part of the code writing process. And we often call bugs problems that manifest themselves in production or when testing code written a few days ago; probably because they are harder to catch (the code has already forgotten). In any case, if the code does not do what it should, it is a bug and needs to be caught and fixed.

4 pillars of effective debugging



Debugging technique
  1. Describe the bug. Collect all the information to fully describe the symptoms of the bug, focusing on when the symptoms appear and when not.
  2. Fix the bug. Describe the sequence of actions that always leads to the appearance of a bug. So you are sure to correctly identify the conditions leading to the appearance of symptoms of the bug. Check that the symptoms do not appear under other conditions.
  3. Locate the bug. Make sure that you can describe the exact cause of the bug and that the description corresponds with steps 1 and 2.
  4. Design and apply the solution. Determine if you are struggling with the true cause of the bug or its symptoms. Write the code.
  5. Check the solution. Check that the symptoms no longer appear when performing the steps described in step 2.
  6. Perform regression testing. Check that there are no new bugs.
  7. Apply the changes. Transfer changes to production.

If you use TDD, a bug means one of three things: the requirements were not correctly translated into tests; one of the available tests is incorrect (does not test what it should); some kind of test is missing. Fixing a bug (step 2) is a study of these three problems by correcting or adding tests; verification of the solution (step 5) means writing new tests; regression testing (step 6) means running the right test sets; application of the solution includes cataloging new tests.


Using breakpoints


Many developers do not know all the debugging capabilities in Visual Studio, because debugging is “already working”. For example, although every VS developer is familiar with breakpoints, many do not know what can be done in the Breakpoints window.
')


To open the Breakpoins window, select Debug | Windows | Breakpoints; the window displays a list of all breakpoints you set. If you are not sure which point corresponds to which line of code, simply double-click on it and the code associated with it will open in the editor.

Having defined the desired point, you can control what happens when it is triggered. I have seen developers who check the same variables over and over again, putting a breakpoint in the loop. On the right click on the breakpoint, selecting When Hit (trigger condition), you can specify a message that is displayed in the Intermediate window every time it is triggered. You can include some constants in the message: for example, using $ Caller, you can print the name of the method that caused the code that contains the breakpoint. You can also include any variables by enclosing them in braces: for example, {Me.NameTextBox.Text} in the message displays the value of the Text field.

Another possibility of the dialogue When Hit allows you to specify whether the program should stop at the breakpoint. If you select a stop, you will see each message at the time of its creation; otherwise, you can view all messages after the program has run.

If you want to stop execution only under certain conditions, you can select the Condition or Hit Count options. The Condition option allows you to specify a logical condition under which a stop will occur (for example, Position> 30). You can also stop if one of the variables has changed since the last stop. The Hit Count option terminates execution only if the breakpoint has fired the nth time (or every n times). This is especially useful when you need to stop somewhere at the end of a cycle.

By the way, my experience says that if problems arise in some part of the application, they will continue to arise there. If your experience says the same thing, you will like the additional features of Visual Studio 2010. You can give the breakpoint names, so as not to forget what each of them is for, and export them to an XML file. The next time you need them, you can import them and start debugging. Import / export can be done using the toolbar at the top of the Breakpoints window.

Show and skip code


I like code generation (I wrote a book on how to do this in .NET). But walking on the code generated by the studio and the framework, as a rule, does not give me anything useful. And since it does not help to find the problem, it makes the debugging process less productive and it is better to avoid it.

In any version of Visual Studio, under Debug | In the General Settings dialog, you can select the Just My Code option and stop seeing the code that you did not write. If you later need to disable it (for example, if an exception occurs somewhere in the generated code), you can do this by selecting Options and Settings in the Debug menu ( this item is only in VS2010 - note. ).

If you are tired of walking through some part of your code, you can use one of two attributes. Put the DebuggerHidden attribute on the method and you will never fall into this method. If you put the DebuggerNonUserCode attribute, you will not get into it when the Just My Code option is on and you will be turned off. I recommend that you use the second method.

On the other hand, if the error occurs somewhere in the Microsoft .NET Framework code, you may need to go through not only the generated code, but also the code of the framework classes. And you can do it! First, make sure that the option Just My Code is disabled. Then in the Options and Settings dialog in the Symbols section, select Microsoft Symbol Server (in VS 2010) or set the symbol path as referencesource.microsoft.com/symbols referencesource.microsoft.com/symbols (in VS2008). This will allow you to load characters that support walking around the .NET class code. However, you still need to download them. In VS2010, you can click the Load All Symbols button, but you need to be patient while downloading.

To select a specific assembly (or if you are using VS2008), in the debugging process stop mode, open the Modules window and in the list of DLLs loaded by your application, right-click on the desired DLL and select Load Modules to load the symbols for this DLL. Of course, you still have to wait, but not for so long.

I am one of those who write useful code in properties and want to be able to debug them step by step. Starting with VS2008SP1, an option appeared (Step over properties and operators), which turns off step-by-step debugging of properties and operators. And in VS2010 it is on by default, so you may need to turn it off.

Data visualization


Oddly enough, many developers are not familiar with data visualizers in Visual Studio. If, in stop mode, hover the mouse over the variable, a prompt with the value of this variable will pop up. An icon with a magnifying glass may also appear - clicking on it will open the value of the variable in the default visualizer. If a drop-down arrow appears next to the icon, a click on the arrow will show other visualizers for this data type. For example, text, XML and HTML visualizers will be shown for a string variable. If you store it in an HTML string, the HTML renderer will help you understand how it will look in the browser.

You can also use visualizers in the Watch, Autos and Locals windows, but if you watch a variable very often, you can click on the thumbtack at the end of the tooltip to “pin” it on this place. Then the next time you view this part of the code, the prompt will pop up automatically.

Speaking of tips, you can change the value of a variable with their help. In VS2010, even more: the hint can be made to hang in the window, the entire debugging session exists, and even after it ends, it will display the value of the variable from the last session. However, the coolest tools (Debugger Canvas and IntelliTrace) are available only in VS2010 Ultimate Edition.

Only in VS2010 Ultimate Edition
The editor in the studio allows you to look only at one piece of code at a time. But a lot of bugs result from interactions between different parts of the code. Debugger Canvas allows you to see all your code at once, moving between modules and approximating the desired part.

When the breakpoint is triggered, you need to understand how you got here. You can use the Call Stack window, but you will not see what happened at the earlier stages (as an option, you can put a bunch of breakpoints and pass them sequentially, tracking variables).

If Debugger Canvas allows you to look “through modules”, then IntelliTrace means “through time”, which gives an understanding of how you got to this breakpoint. IntelliTrace collects and displays debug information that was available at previous points in the debugging session.

Even better, Debugger Canvas and IntelliTrace work in conjunction: in Debugger Canvas there is an option that allows you to see the IntelliTrace logs next to the code.


External tools


Visual Studio is not the only debugging tool, there are any number of external and third-party tools that you can add to the piggy bank. I will stop here only on some free ones.

Not all external tools are made by third-party manufacturers. If you are writing a Windows service, then you know that debugging them is not an easy task. Although you can connect to them for debugging, by this time the OnStart code and initialization will be completed. If the bug does not allow the service to start, you just have to guess what went wrong, instead of collecting information to describe the problem.

In this situation, you can configure Just-in-Time (JIT) debugging and autostart - the debugging session starts when the service starts or when an error occurs. But to do this, you need to use external tools.

Since JIT debugging is beyond the scope of this article, you can refer to the corresponding article in MSDN . This article suggests using the Global Flags Editor (gflags.exe); in case you can't find it, how to tweak the registry to enable JIT debugging is described. However, you will have to learn how to use WinDbg.

WinDbg: outside of the Visual Studio debugger
If you're interested in debugging deeper than the source code, the Microsoft .NET Framework includes some great tools.
Here are a few of them:
  • Windows Debugger (WinDbg.exe)
  • SOS Debugging Extension (SOS.dll, which can be used in the Visual Studio console or with WinDbg.exe)
  • Assemble Binding Log Viewer (Fuslogvw.exe, which I discussed on the .NET Tips blog )


If you haven't used WinDbg before, it’s not as bad as it sounds - WinDbg has a GUI (unlike console tools like NTSD, KD and CBD) and can load PDB files with debugging symbols for your application (just make sure compiled your application in debug mode and the character file is guaranteed to work). In addition to SOS, there are several other WinDbg extensions to perform typical debugging tasks.
However, the most useful tool for use with WinDbg is M ario Hewardt, Patrick Dussud's Advanced .NET Debugging (Addison-Wesley Professional, 2009) . It does not just tell you how to use all these tools, but it does in the context of trapping typical .NET problems.


Third-party visualizers


I have already spoken about Visual Studio visualizers, but there are still many third-party ones. DotNetDan's DataSet Visualizer is very wonderful if you need to know what is in the dataset (I mentioned it on the blog )



Since that time, I have already discovered the RightHand DataSet Visualizer and started using it. This is an MDI application that allows you to open a window for each dataset table. In addition, the Relations window shows the tables associated with the currently viewed.

A grid that displays a table is not simple - you can drag a column to the rectangle at the top of the window to group your table by this column. You can also change the data in the dataset and change the RowState filter to display only rows with a specific RowState (for example, only deleted ones). You can also watch (and change) some dataset properties. And you can even upload datasets to an XML file or load test data from previously saved.

It should be noted that DotNetDan's DataSet Visualizer loads data faster, so I left it in case all the power of RightHand is not needed.

There is also a Web Visualizer for ASP.NET applications. This visualizer is available on the tooltip of any ASP.NET page object (including Me and this in ASP.NET code)

Using the Web Visualizer, you can view any data from the Server Variables collection of the Server object and the Forms collection of the Request object. You can also view the browser query string and the contents of the Session and Application objects. However, in the case of Session and Application for any objects except scalar data, you will only see the name of the object type.

There are other visualizers, including those that allow you to view Cache and LINQ queries to the Entity Framework (EF), and also allow you to see the SQL at the output of LINQ queries to EF. The only sad thing is that there is no single catalog of visualizers.

Not all, but many can be found through the Visual Studio Extension Manager. Including, ASP.NET MVC Routing Visualizer. If you use routing in ASP.NET MVC or in simple ASP.NET, this tool is useful to you. The interaction between routing rules can produce unexpected results (“Why do I get this page?”), And debugging these rules can be difficult. The visualizer allows you to enter URLs and see how the router decodes them, including information about which rule is used for each URL. To use it in stop mode, switch to your global.asax file and hover over RouteTable. When a tooltip appears, scroll to the Routes collection and click on the magnifying glass icon.

Tracing


Tracing is by definition unattractive. However, when in production you run into one of the elusive bugs that are difficult to repeat (and that appear and disappear by themselves), tracing is the only way to get the information you need. To do this, firstly, you need to organize the recording of messages in the log, which will give you information to catch the bug. But for this information to be useful, you need a tool to analyze the contents of the log.

Although there are many packages in the .NET world for tracing, I use log4net. Among other features, log4net allows me to embed debugging messages in the code and then enable or disable them while I work without having to rebuild the application. One note: log4net is a very flexible tool and perhaps more than what you need.

When it comes to reading the resulting logs, I use the Lizard Labs Log Parser Lizard. In the free version, some features are limited (the price is paid - about $ 25), but I never needed them. Log Parser Lizard uses SQL-like syntax for building queries to logs (including CSV and XML files) and understands out of the box the log formats for IIS, Windows events and log4net. The results are displayed in a table, which makes it look like Server Explorer, with which I really enjoy working.

Conclusion


All these tools are useful, but do not forget that the most important is the correct debugging technique. Tools can help you find and fix a bug, but it is the debugging technique that allows you to develop and apply a solution.

Source: https://habr.com/ru/post/149125/


All Articles