Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Effective Debugging in ASP.NET

0.00/5 (No votes)
29 Jun 2009 1  
A simple but effective way of debugging in your ASP.NET application

Introduction

Effective debugging is a key part of effective software development. If you do not realize this statement or even do not appreciate this axiom in software development, this article would not benefit you much. If you are still reading, this article aims to provide a simple but powerful approach (not ready solution) for debugging contents of objects in ASP.NET. Actually you could use this approach for any other language or .NET area by simply using another type of control/debugging logic.

Background

Often in the code, you have an object having contents you would like to see at a specific run time or when the page is loaded. Often you do think that some data structures held specific values yet your program behaves in a way telling you that your assumptions were wrong, but you could not see it because you did not have a proper means for seeing what was in those data structures.

The Approach

The approach consists in using a simple control which renders the contents of a string, which happen to be nicely formatted HTML string, produced by dedicated debugger classes, which contain the logic of converting the contents of custom objects (DataSets, DataReaders, YourFacyCoolTypes) to a simple HTML user-friendly rendering string.

The Code

The code consists of only one simple control you would simply copy paste to your App_Code folder (and probably rename the namespaces ;)). Here it is:

//For docs, read the comments. For legal disclaimer, see the bottom of this file
using System;
using System.Web;

namespace GenApp.Gui.Controls
{
    /// <summary>
    /// A simple control to present debug data. 
    /// Note it inherits the Control class 
    /// </summary>
    public class DebugDumper : System.Web.UI.Control
    {
        #region Text
        /// <summary>
        /// the debugging text to present
        /// </summary>
        private string _Text;
        public string Text
        {
            get
            {
                //use ViewState if you want also
                return System.Convert.ToString(
                HttpContext.Current.Session["global." + 
                this.ID + "Text"]);

            } //eof get

            set
            {
                _Text = value;
                HttpContext.Current.Session["global." + 
                this.ID + "Text"] = value;
            }
        } //eof prop
        #endregion Text


        public DebugDumper(string msg, string debugString)
        {
            this.Text = " " + msg + "  " + debugString;
        }
    
    /// <summary>
    /// Renders the contents of the control 
    /// by using the debug string passed on creation
    /// </summary>
    /// <param name="writer">The <see cref="HtmlTextWriter"/> to write to.</param>

   protected override void Render(System.Web.UI.HtmlTextWriter writer)
   {
    //todo: add here logging according to log level
    writer.Write("<div><p>");
    string echo = this.Text ?? " null debug string passed " ;
    writer.Write( echo ); 
    writer.Write("</p></div>");
    base.Render(writer);

   } //eof method 
  } //eof class 
} //eof namespace 

//Legal disclaimer:
//You could do anything you want with this code. 
//Everything is on your own responsibility. 
//All trademarks belong to their respective owners. 

Example HtmlDebugger Class

Now the key point here is to realize that here I am using my HtmlDebugger class which "knows" how to debug DataSet objects, IDataReader objects and a custom list of my application which contains a custom Msg object just for demonstration purposes. (Delete the DebugMsgList, while copy pasting since you will not know what is the Msg class of my app). Most probably you do have your own debug classes which take specific objects as parameters and do return strings showing their content. One good example would be the Object Dumper by Piero Viano. Most probably your debugging classes do debug more nicely the objects in your app, but for the purpose of this article, I would have to show my HtmlDebugger class:

using System;
using System.Text.RegularExpressions;
using System.Data;
using System.Collections.Specialized;
using System.Text;

namespace GenApp.Utils.Log
{
/// <summary>
///Debugs passed objects and returns ready formatted HTML with the objects values
/// </summary>
public class HtmlDebugger
{
public static string DebugDataSet(string msg, DataSet ds)
{
StringBuilder sb = new StringBuilder();

sb.Append("<p> START " + msg + "</p>");
if (ds == null)
return msg + " null ds passed ";
if (ds.Tables == null || ds.Tables.Count == 0)
return msg + " no tables in ds ";

sb.Append("<p> DEBUG START --- " + msg + "</p>"); 
foreach (System.Data.DataTable dt in ds.Tables)
{
sb.Append("================= My TableName is " +
dt.TableName + " ========================= START");
sb.Append("<table>\n");

int colNumberInRow = 0;

foreach (System.Data.DataColumn dc in dt.Columns)
{
sb.Append(" <th> ");
sb.Append(" |" + colNumberInRow + "| ");
sb.Append(dc.ColumnName + " </th> ");

colNumberInRow++;
} //eof foreach (DataColumn dc in dt.Columns)

int rowNum = 0;

foreach (System.Data.DataRow dr in dt.Rows)
{
string strBackGround = String.Empty;
if (rowNum% 2 == 0)
strBackGround = " bgcolor=\"#D2D2D2\" "; 
sb.Append("\n " + rowNum + "<tr " + strBackGround + " >");
int colNumber = 0;
foreach (System.Data.DataColumn dc in dt.Columns)
{
sb.Append("<td> |" + colNumber + "| ");
sb.Append(dr[dc].ToString() + " </td>");
colNumber++;
} //eof foreach (DataColumn dc in dt.Columns)
rowNum++;
sb.Append("</tr>");
} //eof foreach (DataRow dr in dt.Rows)
sb.Append(" \n");
sb.Append("</table>");
} //eof foreach (DataTable dt in sb.Append.Tables)
sb.Append("<p> DEBUG END--- " + msg + "</p>"); 
return sb.ToString();
}//eof method 

public static string DebugMsgList
	(string msg, System.Collections.Generic.List<GenApp.Dh.Msg> listMsgs)
{
System.Text.StringBuilder echo = new System.Text.StringBuilder();
if (listMsgs == null)
return "null listMsgs passed for debugging ";
if (listMsgs.Count == 0)
return "listMsgs.Count == 0"; 
echo.Append("<table>");
for (int msgCounter = 0; msgCounter < listMsgs.Count; msgCounter++)
{
GenApp.Dh.Msg objMsg = listMsgs[msgCounter];
string strBackGround = String.Empty;
if (msgCounter % 2 == 0)
strBackGround = " bgcolor=\"#D2D2D2\" "; 
echo.Append("<tr" + strBackGround + ">");
echo.Append("<td>msg.MsgKey</td> <td> " + objMsg.MsgKey + "</td>");
echo.Append("<td>msg.MsgId</td><td>" + objMsg.MsgId + "</td>");
echo.Append("</tr>");
} //eof foreach 

echo.Append("</table>");
return echo.ToString();
} //eof method 

public static string DebugIDataReader(string msg, IDataReader rdr)
{
StringBuilder sb = new StringBuilder();
if (rdr == null)
return " <p> IDataReader rds is null </p>";
sb.Append("DEBUG START ---" + msg);
sb.Append("<table>");
 int counter = 0; 
 while (rdr.Read() )
 {
 string strBackGround = String.Empty;
 if (counter % 2 == 0)
 strBackGround = " bgcolor=\"#3EBDE8\" "; 
 sb.Append("<tr" + strBackGround + ">");
 for (int i = 0; i < rdr.FieldCount; i++)
 {
  sb.Append("<td>");
  sb.Append(rdr[i].ToString() + " ");
  sb.Append("<td>");
 } //eof for 

  sb.Append("</br>");
  sb.Append("</tr>");
  counter++; 
  }

  sb.Append("<table>");
  sb.Append("DEBUG END ---" + msg);
  return sb.ToString(); 
  } //eof method 

 public static string DumpListDictionary(string msg , ListDictionary list)
 {
 if (list == null)
   return "<p> null list passed </p>";
 if (list.Count == 0)
   return "<p> list.Count = 0 </p> "; 

 System.Text.StringBuilder sb = new System.Text.StringBuilder();

 sb.Append("<p> START DUMP " + msg + " </p>");
 sb.Append("<table>");

 int counter = 0; 
 foreach (object key in list.Keys)
 {
 string strBackGround = String.Empty;
 if (counter % 2 == 0)
 strBackGround = " bgcolor=\"#D2D2D2\" ";

 sb.Append("<tr" + strBackGround + "><td> key -   </td><td> " + key.ToString());
 sb.Append("</td><td>===</td><td>value - </td><td> " + list[key] +  "</td></br></tr>");
 counter++;
 } //eof foreach 

 sb.Append("</table>");
 sb.Append("<p> END DUMP " + msg + " </p>");
 return sb.ToString();
  } //eof method 
 } //eof class 
} //eof namespace 

Using the Code

You would use the code from the page's code behind as follows:

protected override void CreateChildControls()
{
  base.CreateChildControls();

//... Populating the dataset object 2
        panTxtHolder.Controls.Add(
            new GenApp.Gui.Controls.DebugDumper("some debug msg ",
                GenApp.Utils.Log.HtmlDebugger.DebugDataSet(
                "another debug msg", dsForUserDetails)));

} //eof method 

Here panTextHolder is the Panel I have already populated in the page of this code behind.
dsForUserDetails is my DataSet I want to debug during the call.

Points of Interest

It would be nice to implement a control, which sits on the top of the site master and has the true, false radio button to see debugging info with the according event handler so that a user entitled to see debugging info would be able to switch between regular and debugging view. I wonder also if OnDataBind would be a better place to implement the adding of the text to the control... If you have some thoughts, please comment below. It would be nice to implement a custom log4net appender based on this approach. It would be even nicer that this would be triggered by dynamic logging settings - e.g. when the app is in production and something is really wrong, the admin would impersonate the person having the problems and dynamically enable the debugging and provide the software developer maintaining the app the valuable info. If you have implemented something like this, I would be glad to hear what your approach was for solving the issue.

History

  • 29th June, 2009: Initial post

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here