Search code examples
asp.netasp.net-mvcstringhttpmoduleresponse.write

How could I insert a string into the response stream anywhere I want?


There may be an easy way to do this but I can't see it...

I created a simple Http Module that starts a timer on the PreRequestHandler and stops the timer on the PostRequestHandler to calculate the time it took the page to load.

I then create some simple html and write my results to Response.Write. Since I'm doing this in the PostRequestHandler it's adding my results after the </html> tag. That's fine for testing but I need in a scenario where the page needs to validate.

I can't seem to figure out how I could manipulate the Response object to insert my results before the </body> tag. Response.Write and Response.Output.Write don't have that flexibility and I couldn't see a way to work with the Response as a string. Am I missing something easy?


Solution

  • To do this, you'd have to implement your own stream object and use that as a filter for your response.

    For isntance:

    public class TimerStream : Stream
    {
        private Stream inner { get; set; }
        private StringBuilder   responseHtml;
    
        public TimerStream(Stream inputStream) { 
            inner = inputStream; 
            responseHtml = new StringBuilder();
            // Setup your timer
        }
    
        /* Filter overrides should pass through to inner, all but Write */
        public override void Write(byte[] buffer, int offset, int count)
        {
            string bufferedHtml = System.Text.UTF8Encoding.UTF8.GetString (buffer, offset, count);
            Regex endTag = new Regex ("</html>", RegexOptions.IgnoreCase);
    
            if (!endTag.IsMatch (bufferedHtml))
            {
                responseHtml.Append(bufferedHtml);
            }
            else
            {
                // insert timer html into buffer, then...
                responseHtml.Append (bufferedHtml);
                byte[] data = System.Text.UTF8Encoding.UTF8.GetBytes (responseHtml.ToString ());            
                inner.Write (data, 0, data.Length);            
            }
        }
    }
    

    Then, in your HttpModule, you'd add this to your BeginRequest:

    // Change the Stream filter
    HttpResponse response = context.Response;
    response.Filter = new TimerStream(context.Response.Filter);