Search This Blog

2009-06-29

Effective debugging in asp.net

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 file
using 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. 
//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 
where 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 wander also if OnDataBind would be better place to implement the adding of the text to the control ... If you you have some thoughts comment bellow ... 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 empersonate the person having the problems and enable dynamically 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 here what was your approach for solving the issue.

Labels

perl (41) Cheat Sheet (25) how-to (24) windows (14) sql server 2008 (13) linux (12) oracle (12) sql (12) Unix (11) cmd windows batch (10) mssql (10) cmd (9) script (9) textpad (9) netezza (8) sql server 2005 (8) cygwin (7) meta data mssql (7) metadata (7) bash (6) code generation (6) Informatica (5) cheatsheet (5) energy (5) tsql (5) utilities (5) excel (4) future (4) generic (4) git cheat sheet (4) html (4) perl modules (4) programs (4) settings (4) sh (4) shortcuts (4) поуки (4) принципи (4) Focus Fusion (3) Solaris (3) cool programs (3) development (3) economy (3) example (3) freeware (3) fusion (3) logging (3) morphus (3) mssql 2005 (3) nuclear (3) nz (3) parse (3) python (3) sftp (3) sofware development (3) source (3) sqlplus (3) table (3) vim (3) .Net (2) C# (2) China (2) GUI (2) Google (2) GoogleCL (2) Solaris Unix (2) ascii (2) awk (2) batch (2) cas (2) chrome extensions (2) code2html (2) columns (2) configuration (2) conversion (2) duplicates (2) excel shortcuts (2) export (2) file (2) free programs (2) informatica sql repository (2) linux cheat sheet (2) mssql 2008 (2) mysql (2) next big future (2) nsis (2) nz netezza cheat sheet (2) nzsql (2) ora (2) prediction (2) publish (2) release management (2) report (2) security (2) single-click (2) sqlserver 2005 (2) sqlserver 2008 (2) src (2) ssh (2) template (2) tools (2) vba (2) video (2) xlt (2) xml (2) youtube videos (2) *nix (1) .vimrc (1) .virmrc vim settings configs (1) BSD license (1) Bulgaria (1) Dallas (1) Database role (1) Dense plasma focus (1) Deployment (1) ERP (1) ExcelToHtml (1) GD (1) GDP (1) HP-UX (1) Hosting (1) INC (1) IT general (1) ITIL management bullshit-management (1) IZarc (1) Java Web Start (1) JavaScript anchor html jquery (1) Khan Academy (1) LINUX UNIX BASH AND CYGWIN TIPS AND TRICKS (1) Linux Unix rpm cpio build install configure (1) Linux git source build .configure make (1) ListBox (1) MIT HYDROGEN VIRUS (1) OO (1) Obama (1) PowerShell (1) Run-time (1) SDL (1) SIWA (1) SOX (1) Scala (1) Services (1) Stacks (1) SubSonic (1) TED (1) abstractions (1) ansible hosts linux bash (1) ansible linux deployment how-to (1) ansible yum pip python (1) apache (1) apache 2.2 (1) application life cycle (1) architecture (1) archive (1) arguments (1) avatar (1) aws cheat sheet cli (1) aws cli (1) aws cli amazon cheat sheet (1) aws elb (1) backup (1) bash Linux open-ssh ssh ssh_server ssh_client public-private key authentication (1) bash perl search and replace (1) bash stub (1) bin (1) biofuels (1) biology (1) books (1) browser (1) bubblesort (1) bugs (1) build (1) byte (1) cas_sql_dev (1) chennai (1) chrome (1) class (1) claut (1) cmdow (1) code generation sqlserver (1) command (1) command line (1) conf (1) confluence (1) console (1) convert (1) cool programs windows free freeware (1) copy-paste (1) csv (1) ctags (1) current local time (1) cygwin X11 port-forwarding mintty xclock Linux Unix X (1) cygwin bash how-to tips_n_tricks (1) cygwin conf how-to (1) data (1) data types (1) db2 cheat sheet (1) db2 starter ibm bash Linux (1) debt (1) diagram (1) dictionaries (1) digital (1) disk (1) disk space (1) documentation (1) dos (1) dubai (1) e-cars (1) electric cars (1) electricity (1) emulate (1) errors (1) exponents (1) export workflow (1) extract (1) fast export (1) fexp (1) file extension (1) file permissions (1) findtag (1) firewall (1) for loop (1) freaky (1) functions (1) fusion research (1) german (1) git gitlab issues handling system (1) google cli (1) google code (1) google command line interface (1) gpg (1) ha (1) head (1) helsinki (1) history (1) hop or flop (1) host-independant (1) how-to Windows cmd time date datetime (1) ibm db2 cognos installation example db deployment provisioning (1) ideas (1) image (1) informatica oracle sql (1) informatica repo sql workflows sessions file source dir (1) informatica source files etl (1) install (1) isg-pub issue-tracker architecture (1) it management best practices (1) java (1) jump to (1) keyboard shortcuts (1) ksh (1) level (1) linkedin (1) linux bash ansible hosts (1) linux bash commands (1) linux bash how-to shell expansion (1) linux bash shell grep xargs (1) linux bash tips and t ricks (1) linux bash unix cygwin cheatsheet (1) linux bash user accounts password (1) linux bash xargs space (1) linux cheat-sheet (1) linux cheatsheet cheat-sheet revised how-to (1) linux how-to non-root vim (1) linux ssh hosts parallel subshell bash oneliner (1) london (1) make (1) me (1) metacolumn (1) metadata functions (1) metaphonre (1) method (1) model (1) movie (1) multithreaded (1) mysql cheat sheet (1) mysql how-to table datatypes (1) n900 (1) nano (1) neteza (1) netezza bash linux nps (1) netezza nps (1) netezza nps nzsql (1) netezza nz Linux bash (1) netezza nz bash linux (1) netezza nz nzsql sql (1) netezza nzsql database db sizes (1) non-password (1) nord pol (1) nps backup nzsql schema (1) number formatting (1) nz db size (1) nz table count rows (1) nzsql date timestamp compare bigint to_date to_char now (1) on-lier (1) one-liners (1) one-to-many (1) oneliners (1) open (1) open source (1) openrowset (1) openssl (1) oracle PL/SQL (1) oracle Perl perl (1) oracle installation usability (1) oracle number formatting format-model ora-sql oracle (1) oracle templates create table (1) oracle trigger generic autoincrement (1) oracle vbox virtual box cheat sheet (1) oracle virtual box cheat sheet (1) outlook (1) parser (1) password (1) paths (1) perl @INC compile-time run-time (1) perl disk usage administration Linux Unix (1) perl modules configuration management (1) permissions (1) php (1) picasa (1) platform (1) postgreSQL how-to (1) powerShell cmd cygwin mintty.exe terminal (1) ppm (1) predictions (1) prices (1) principles (1) productivity (1) project (1) prompt (1) proxy account (1) public private key (1) publishing (1) putty (1) qt (1) read file (1) registry (1) relationship (1) repository (1) rm (1) scala ScalaFmt (1) scp (1) scripts (1) scsi (1) search and replace (1) sed (1) sendEmail (1) sh stub (1) shortcuts Windows sql developer Oracle (1) sidebar (1) silicon (1) smtp (1) software procurement (1) sofware (1) sort (1) sql script (1) sql_dev (1) sqlcmd (1) sqlite (1) sqlite3 (1) sshd (1) sshd cygwin (1) stackoverflow (1) stored procedure (1) stub (1) stupidity (1) subroutines (1) svn (1) sysinternals (1) tail (1) tar (1) temp table (1) templates (1) teradata (1) terminal (1) test (1) testing (1) theory (1) thorium (1) time (1) tip (1) title (1) tmux .tmux.conf configuration (1) tmux efficiency bash (1) tool (1) ui code prototyping tips and tricks (1) umask Linux Unix bash file permissions chmod (1) url (1) urls (1) user (1) utility (1) utils (1) vb (1) vbox virtual box cheat sheet (1) vim perl regex bash search for string (1) vim recursively hacks (1) vim starter (1) vim-cheat-sheet vim cheat-sheet (1) vimeo (1) visual stuio (1) warsaw (1) wiki (1) wikipedia (1) window (1) windows 7 (1) windows 8 (1) windows programs (1) windows reinstall (1) windows utility batch perl space Windows::Clipboard (1) wisdoms (1) workflow (1) worth-reading (1) wrapper (1) xp_cmdshell (1) xslt (1) youtube (1)

Blog Archive

Translate with Google Translate

My Blog List

VideoBar

This content is not yet available over encrypted connections.