0

I've enabled trace pageoutput="true" in my web.config and I like the easy way it provides of seeing all this stuff at the bottom of the page.

I'd like to get the same output from trace at the bottom of the output from my httphandler. Is there a way to dump out the same trace info via code that would follow this code:

public class UploadHandler : IHttpHandler
{

    public void ProcessRequest(HttpContext context)
    {
        context.Response.ContentType = "text/plain";
        context.Response.Write("Hello World");
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

I particularly want to see the Forms and QueryString collections but all this gives is "Hello World".

-- edit update 7/25/2009:

    public class UploadHandler : IHttpHandler
    {

    public void ProcessRequest(HttpContext context)
    {
        context.Response.ContentType = "text/plain";
        context.Response.Write("Hello World");

        object htw = new System.Web.UI.Html32TextWriter(context.Response.Output);
        {
            typeof(TraceContext)
                .GetMethod("Render", System.Reflection.BindingFlags.NonPublic)
                .Invoke(HttpContext.Current.Trace, new object[] { htw });
        }

    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

I am also open to any other ideas about how to most easily get a formatted dump of the forms and querystring collections like pageOutput trace does.

John Adams
  • 4,773
  • 25
  • 91
  • 131

3 Answers3

1

You can get your own trace events from HttpContext.Current.Trace.TraceFinished. Unfortunately, the page tracing (which includes all the goodies of Forms, QueryString, etc.) is locked away in internal methods.

If you're okay with reflection, you can call it like:

using (var htw = new System.Web.UI.Html32TextWriter(response.Output)) {
    typeof(TraceContext)
        .GetMethod("Render",BindingFlags.NonPublic | BindingFlags.Instance)
        .Invoke(HttpContext.Current.Trace, new object[] { htw });
}

Reflectoring over System.Web.TraceContext.EndRequest should give you enough to create your own TracingHttpHandler if you can't use reflection.

Edit: It looks like you forgot BindingFlags.Instance. Also, I'm guessing you changed using (var htw = ...) to using (object htw = ...) which would give you the "type must be implicitly convertible to IDisposable" error. If you can't use var, then you'll have to write it as using (Html32TextWriter htw = ...).

Full sample:

<%@ WebHandler Language="C#" Class="UploadHandler" %>

using System;
using System.Web;
using System.Web.UI;
using System.Reflection;

public class UploadHandler : IHttpHandler {
    public bool IsReusable { 
       get { return true; }
    }

    public void ProcessRequest(HttpContext context) {
       // the output will suck as text/plain - Render outputs HTML.
       context.Response.ContentType = "text/html"; 
       context.Response.Write("Hello World!");

       // depending on web.config settings, you may need to enable tracing manually
       HttpContext.Current.Trace.IsEnabled = true;
       // I had to write a custom trace message, or the Request context wasn't captured - YMMV
       HttpContext.Current.Trace.Write(null);

       using (Html32TextWriter htw = new Html32TextWriter(context.Response.Output)) {
          typeof(TraceContext)
              .GetMethod("Render", BindingFlags.NonPublic | BindingFlags.Instance)
             .Invoke(HttpContext.Current.Trace, new object[] { htw });
       } 
    }
}
Mark Brackett
  • 84,552
  • 17
  • 108
  • 152
  • Tried your using block and he complained about having to implement IDisposable so I tried: public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/plain"; context.Response.Write("Hello World"); object htw = new System.Web.UI.Html32TextWriter(context.Response.Output); { typeof(TraceContext) .GetMethod("Render", System.Reflection.BindingFlags.NonPublic) .Invoke(HttpContext.Current.Trace, new object[] { htw }); } } Err on typeof – John Adams Jul 24 '09 at 21:55
  • @John Galt - Html32TextWriter *does* implement IDisposable (http://msdn.microsoft.com/en-us/library/system.web.ui.html32textwriter.dispose.aspx) and typeof is standard C# (http://msdn.microsoft.com/en-us/library/58918ffs(VS.71).aspx). Post all of your code into your question (so it's formatted), and I can check the syntax. – Mark Brackett Jul 24 '09 at 23:14
  • Mark, Thanks for your code and explanation. It worked exactly as I hoped it might and yet I re-read your comment closely - "Unfortunately, the page tracing (which includes all the goodies of Forms, QueryString, etc.) is locked away in internal methods." Is there any relatively simple way I can "dump out" the Forms and Querystring collections with code by extending the routine you've provided here? Or is it just not available inside HTTPHandler? That is, not sure what you mean by "locked away in internal methods". – John Adams Jul 27 '09 at 15:50
  • Mark, ..still not sure what you meant by "Unfortunately, the page tracing (which includes all the goodies of Forms, QueryString, etc.) is locked away in internal methods. BUT - the good news is that I looked closely at the output produced by the code you provided and sure enough- the Form, Querystring collections and others are all formatted just like for an .aspx page. So - thanks very much! – John Adams Jul 27 '09 at 20:03
  • @John Galt - It means there's no *public* API that can be called to get the formatted output. Reflection bypasses the public API, and calls an internal method - nromally only available to MS. Internal methods are, by definition, unsupported - they can be changed or removed by MS at any time and would not be considered "breaking". Also, reflection requires Full Trust - meaning you couldn't run this code on most commercial ASP.NET web hosts. – Mark Brackett Jul 28 '09 at 01:23
0

Actually it's pretty straightforward to get this info from ASP.Net as long as you have the correct exception type. I'm using this in my global.asax error handler for an MVC app to email me the yellow screen of death stack trace I wouldn't normally see;

        // See if ASP.Net has some error handling info for us first
        string htmlError = null;
        var httpException = e as HttpException;
        if (httpException != null)
            htmlError = httpException.GetHtmlErrorMessage();
        else
        {
            // Ok, we'll generate our own then
            var h = new HttpUnhandledException(e.Message, e);
            htmlError = h.GetHtmlErrorMessage();
        }

Notice in the second statement group that I simple wrap whatever exception has been thrown in a HttpUnhandledException() which has the appropriate method and gunk to harvest and spit out all the goodies.

cirrus
  • 5,624
  • 8
  • 44
  • 62
0

I don't think that ASP.NET tracing works except for pages.

Does it matter if the output is at the bottom of the page? What if the output were in a separate file, or in the event log? You could probably do thsi with ASP.NET Health Monitoring.

John Saunders
  • 160,644
  • 26
  • 247
  • 397