Handy ASP.NET Debug Extension Method

Add to FacebookAdd to DiggAdd to Del.icio.usAdd to StumbleuponAdd to RedditAdd to BlinklistAdd to TwitterAdd to TechnoratiAdd to Yahoo BuzzAdd to Newsvine

Most of the programmers I know (myself included) don’t bother with the built in Visual Studio debugging tools. They are slow and resource intensive. Usually, its more efficient to just do one or more Response.Write calls to see key data at key steps.

That can be a hassle, though. Most objects don’t print very well. You have to create a loop or write some LINQ/String.Join to write items in a collection.

Inspiration struck – couldn’t I write an extension method on object to write out a reasonable representation of pretty much anything? I could write out html tables for lists with columns for properties, etc.

Then I thought – I love the javascript debug console in firebug. I can drill down into individual items without being overwhelmed by all of the data at once. Why not have my debug information spit out javascript to write to the debug console? That also keeps it out of the way of the rest of the interface.

Here’s the code:

public static void Debug(this object value)
        {
            if (HttpContext.Current != null)
            {
                HttpContext.Current.Response.Debug(value);
            }

        }

        public static void Debug(this HttpResponse Response, params object[] args)
        {

            new HttpResponseWrapper(Response).Debug(args);
        }
        public static void Debug(this HttpResponseBase Response, params object[] args)
        {

            ((HttpResponseWrapper)Response).Debug(args);
        }
        public static void Debug(this HttpResponseWrapper Response, params object[] args)
        {

            if (Response != null && Response.ContentType == "text/html")
            {
                Response.Write("<script type='text/javascript'>");
                Response.Write("if(console&&console.debug){");

                Response.Write("console.debug(" +
                              args.SerializeToJSON() +
                               ");");
                Response.Write("}");
                Response.Write("</script>");
            }
        }

The various overloads allow:

myObject.Debug();
new {message="test",obj=myObject}.Debug();
Response.Debug("some message",myObject,myObject2);
//etc

The only other thing you’ll need is the awesome JSON.NET library for the .SerializeToJSON() call to work (which turns the .NET object into the form javascript can deal with). Get it here. FYI, the library does choke serializing some complex objects, so occasionally you’ll need to simplify before calling debug.

Advertisements

Some Good Uses for the ASP.NET .ASHX/”Generic Handler”

Add to FacebookAdd to DiggAdd to Del.icio.usAdd to StumbleuponAdd to RedditAdd to BlinklistAdd to TwitterAdd to TechnoratiAdd to Yahoo BuzzAdd to Newsvine

I’ve been developing ASP.NET applications since 2002.  Up until recently, I’d overlooked a pretty useful part of the ASP.NET Framework : Generic Handlers.

Generic Handlers are basically HTTP Handlers that can process requests to exactly one url (Http Handlers are classes that need to be registered in the web.config for what urls they run on, and often manipulate requests/responses that go to/come from .aspx pages). They are “closer to the wire” than .ASPX WebForms or .ASMX WebServices.  They are built with only two requirements, implement:

public void ProcessRequest(HttpContext context);

(this contains the logic for when this page is requested) and, implement:

public bool IsReusable;

(this tells ASP.NET whether it can use one instance to serve multiple requests).

Generic Handlers are similar to web forms – they are reachable by a standard get/post to the url they are located in.  ASP.NET starts you off with context object (passed into the ProcessRequest() function you implement), which you then use to communicate with the request (form and query vals, etc) and the response object (to write info to the browser).  You can decide in what capacity you want that context to have access to the session:read/write, readonly, or none. Unlike web forms, generic handlers skip some of the niceties: the designer/xaml/servercontrol model, themes, viewstate, etc. Thus, generic handlers can be much more efficient for many tasks that make no use of those features.

Here’s a few common tasks where a generic handler would be more suitable than a web form:

  • Writing out the contents of files stored in the db/elsewhere for download
  • Writing out manipulated images, generated graphics, etc
  • Writing out generated PDFs/CSVs etc
  • Writing out data without the webservice overhead
    • xml for other systems or sites
    • html for simple AJAX get requests to replace page content
    • JSON for more advanced ajax data communication
  • Callback urls for data sent from other sites through a http post
  • Building a “REST API”
  • A url that outputs status info about the website, for use by a content switch or other monitoring system
  • Writing out dynamic JS/CSS based on server variables, browser capabilities, etc

Basically, anywhere I found myself before creating an ASPX page, but clearing everything on the .ASPX and using Response.Write()/Response.BinaryWrite() to talk to the browser or another system from the code behind, I should have been using a .ASHX handler instead and saving my webserver some work.

Here is a sample GenericHandler to get you started. It writes out a simple js file that gives you some useful globals you can use in other js files. Its meant to just be an example of the types of things you can do with generic handlers, and doesn’t necessarily produce what you might want in your own dynamic JS file.


    public class SiteJSGlobals : System.Web.IHttpHandler, System.Web.SessionState.IReadOnlySessionState
    {
        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/javascript";

            context.Response.Write("var _g_username='" + context.User.Identity.Name + "';\n");
            context.Response.Write("var _g_usertype='" + context.Session["UserType"] + "';\n");
            context.Response.Write("var _g_browserheight=" + context.Request.Browser.ScreenPixelsHeight + ";\n");
            context.Response.Write("var _g_browserwidth=" + context.Request.Browser.ScreenPixelsWidth + ";\n");
            context.Response.Write("var _g_queryparam='" + context.Request["queryparam"] + "';\n");
            context.Response.Write("var _g_developmentmode=" + context.Request.Url.Host.ToLower().StartsWith("localhost") + ";\n");
            context.Response.Write("var _g_approoturl='" + context.Request.ApplicationPath + "';\n");
        }
        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }