Wednesday, May 13, 2009

ASP.Net Control to Display Session

I wanted to be able to see all my Session data on my webpage, but only when I actually had a debugger attached.  My solution was a two step approach:
  1. Create a user control that ouputs the session into a table
  2. Add that user control to the to the page if a debugger is attached
To accomplish step 1, I created a user control which is located below.  It overrides the Render method, directly writing a text html table to the HtmlTextWriter.  It contains two other methods, one to create the table to display the session information in, iterating over all the values in the session, and another that uses reflection to output the value of all properties of non-simple types.  

public class SessionDisplayControl : UserControl

public SessionDisplayControl()
{
}

protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);
writer.Write(GetOutputState());
}

protected string GetOutputState()
{
System.Text.StringBuilder sb = new System.Text.StringBuilder(2000);
sb.AppendLine("<table border='1' align='center'><tr><td colspan='2'>There are " + Session.Contents.Count + " Session variables</td></tr>");
foreach (string name in Session.Contents)
{
System.Collections.IEnumerable enumeratable = Session[name] as System.Collections.IEnumerable;
if (enumeratable == null || Session[name].GetType() == typeof(String))
{
sb.AppendLine(string.Format(@"<tr><td>{0}</td><td>{1}</td></tr>", HttpUtility.HtmlEncode(name), GetObjectValue(Session[name] ?? "<NULL>")));
}
else
{
sb.AppendLine(@"<tr><td>" + HttpUtility.HtmlEncode(name) + @"</td><td><table border='1'>");
int i = 0;
foreach (object o in enumeratable)
{
sb.AppendLine(string.Format("<tr><td>Item({0})</td>", i++));
sb.AppendLine(string.Format(@"<td>{0}</td></tr>", GetObjectValue(o)));
}
sb.AppendLine(@"</table></tr>");
}
}
sb.AppendLine("</table>");
return sb.ToString();
}

private static string GetObjectValue(Object obj)
{
if (obj is string || obj is bool || obj is int || obj is long || obj is double || obj is decimal || obj is DateTime)
{
return HttpUtility.HtmlEncode(obj.ToString());
}

System.Text.StringBuilder sb = new System.Text.StringBuilder(500);
System.Reflection.PropertyInfo[] properties = obj.GetType().GetProperties();
foreach (System.Reflection.PropertyInfo property in properties)
{
try
{
sb.Append(HttpUtility.HtmlEncode(property.Name));
sb.Append(": ");
sb.Append(HttpUtility.HtmlEncode((property.GetValue(obj, null) ?? "<NULL>").ToString()));
sb.Append("<br/>");
}
catch (Exception ex)
{
sb.Append("ERROR: " + HttpUtility.HtmlEncode(ex.Message) + "<br/>");
}
}
return sb.ToString();
}
}

To accomplish step 2, all that was needed was to override the OnLoad event in my BasePage class from which all other classes in my website inherit, check for a debugger, and add my user control from step 1 to the page if one was attached.

    protected override void  OnLoad(EventArgs e)
{
base.OnLoad(e);
if (System.Diagnostics.Debugger.IsAttached && !IsPostBack)
{
this.Controls.Add(new SessionDisplayControl());
}
}

Now whenever I have a debugger attached my session will be displayed at the bottom of the page.  This has helped me clean up unused session variables numerous times.  Enjoy!

1 comment:

Kyle said...

What you can't click and drag? this sucks