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 powerfull aproach ( 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 holded 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 mean 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 happens to be nicely html formatted 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 leagal disclaimer see the bottom of this fileusing System;
using System.Web;
namespace GenApp.Gui.Controls
{///
/// A simple control to present debug data.
/// Note it inherits the Control class
///
public class DebugDumper : System.Web.UI.Control{#region Text
/// the debugging text to present
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
//Leagal 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 I am using here my HtmlDebugger class which "knows" how to debug DataSet objects , IDataReader objects and a custom list of my application which contains a custom Msg objects 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 a specific objects as parameters and do return strings showing their content. I 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
dsForUserDetails is my DataSet I want to debug during the call.
No comments:
Post a Comment
- the first minus - Comments have to be moderated because of the spammers
- the second minus - I am very lazy at moderating comments ... hardly find time ...
- the third minus - Short links are no good for security ...
- The REAL PLUS : Any critic and positive feedback is better than none, so your comments will be published sooner or later !!!!