Click here to Skip to main content
Click here to Skip to main content

Removing White Chars from ASP.NET Output using Response.Filter property

, 7 Feb 2005
Rate this:
Please Sign up or sign in to vote.
This article shows how to remove unwanted white chars from each line, and some of the new line chars too. My code correctly handles scripts embedded in HTML pages.

Introduction

This article demonstrates how to remove unwanted white characters from ASP.NET output. I present how to use HttpResponse.Filter property to achieve this effect.

Background

During my work on an ASP.NET site, I realized that pages sent to the browser by the server contained many white characters at the beginning of each line. I browsed MSDN for something to fix this, and I found HttpResponse.Filter property. HttpResponse works in an easy way - all ASP.NET output goes through it. So my task looked easy - create my own Stream implementation and trim each written line in Write() function.

First version

First version was very simple:

public class TrimStream : Stream
{
    private Stream stream;
    private StreamWriter streamWriter;
    
    public TrimStream(Stream stm)
    {
        stream = stm;
        streamWriter = new StreamWriter(stream, System.Text.Encoding.UTF8);
    }
    
    public override void Write(byte[] buffer, int offset, int count)
    {
        MemoryStream ms = new MemoryStream(buffer, offset, count, false);
        StreamReader sr = new StreamReader(ms, System.Text.Encoding.UTF8);
        bool bNewLine = false;
        string s;
        while ((s = sr.ReadLine()) != null)
        {
            s = s.Trim();
            if (s != "")
            {
                if (bNewLine)
                {
                    streamWriter.WriteLine();
                    bNewLine = false;
                }

                streamWriter.Write(s); 

                //new line chars should be emitted 
                //only when line doesn't end with '>'
                if (s[s.Length-1] != '>')
                    bNewLine = true;
            }
        }
        streamWriter.Flush();
    }
    
    /* other overrided Stream functions and properties goes here */
}

This code reads lines from the input stream, trims them, and writes to output stream only if the line is not empty. New line characters were written only when a line doesn't end with '>' char.

Unfortunately, I quickly realized that larger pages (> 30K or something like that) are written to output stream by multiple calls to Write() - on one of my pages, I found a text input box instead of a checkbox (my code replaced <input type="checkbox"> with <input type="\ncheckbox">). So I decided to completely rewrite my code, and manually handle each character in order to correctly handle this situation.

Current version

In the current version, I read all characters from the input stream, and manually analyze them line-by-line. Special handling is needed for the first and the last line:

  • on last line, I save white chars from the end of the line (they may be important if my "last line" ends somewhere in the middle of a real line);
  • on first line, I write saved white chars if they are really needed.

I also changed the logic that controls when a new line character is written - now it's emitted when neither previous line ends with '>' nor next line begins with '<'. I check this after trimming white chars and removing empty lines.

This approach is safe for scripts embedded in a page - their lines are only trimmed, and empty lines are removed. If you insert this script in an HTML page:

<script language="javascript">
<!--
function test()
{
    alert('test');
}
//-->
</script>

My code changes it as follows:

<script language="javascript"><!--
function test()
{
alert('test');
}
//--></script>

Code description

bNewLine and bLastCharGT variables are used for deciding when to write a new line character before the next line. In arBlanks array are stored white chars between calls to Write(), if any was found on end of last line. This array can be zero-sized too - in this case, last char in line was non-blank, and that doesn't end with '\n'. This is important information - in this case, a new line char shouldn't be emitted if in first line (on next call to Write are non-blank chars).

This code analyzes chars looking for '\n' char (it splits lines). When this char is found, you can find the following situations:

  • first line - if arBlanks is not null, its contents are written, and all white chars to the beginning of the current line should be written to the output stream too;
  • any line with non-blank chars - this code writes it (excluding white chars at the begin and end of it);
  • last line - if last char on this line is other than '\n', all white chars from end of this line should be saved to arBlanks array for next call to Write().
public class TrimStream : Stream
{
    private Stream stream;
    private StreamWriter streamWriter;

    private Decoder dec;

    public TrimStream(Stream stm)
    {
        stream = stm;
        streamWriter = new StreamWriter(stream, System.Text.Encoding.UTF8);

        dec = Encoding.UTF8.GetDecoder();
    }

    /// <span class="code-SummaryComment"><summary>
</span>
    /// Flag - write '\n' before next line
    /// <span class="code-SummaryComment"></summary>
</span>
    private bool bNewLine = false;
    /// <span class="code-SummaryComment"><summary>
</span>
    /// Flag - lash non-blank char in line was '>

Using the code

An instance of this class must be created on each request and assigned to the current Request.Filter property. You can do it in almost any event generated by the HttpApplication class. But if you have pages that renders something different than html code (text/html MIME type), you should take care of this. In this case, you should test the current MIME type and create (or not) this filter in HttpApplication.PostRequestHandlerExecute event handler:

private void Global_PostRequestHandlerExecute(object sender, System.EventArgs e)
{
    if (Response.ContentType == "text/html")
        Response.Filter = new TrimStream(Response.Filter);
}

Points of Interest

HttpResponse.Filter property gives us an entry point to connect our output filters to an ASP.NET output stream. This property can be used to connect any combination of filters, e.g., my filter and compression filter:

Response.Filter = new TrimStream(new CompressStream(Response.Filter));

Also, this is an interesting alternative to IHttpModule-based filters.

History

  • 2/7/2005 - First version.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Daniel Fruzynski
Web Developer
Germany Germany
No Biography provided

Comments and Discussions

 
GeneralMy vote of 2 PinmemberMember 860510229-Apr-12 7:19 
Poorly documented variables and seems way overly complicated just to remove to white space - OTT
QuestionMultiple write problem Pinmemberskrblyk2-Apr-12 3:31 
QuestionThis trick will prevent ASP.net AJAX from function properly PinmemberMember 31845941-Apr-09 23:20 
AnswerRe: This trick will prevent ASP.net AJAX from function properly PinmemberMagomed Abdurakhmanov23-May-09 9:26 
GeneralDiamond like � Character Pinmemberqurban ali26-Aug-08 2:59 
GeneralDiamond like � Character Pinmemberqurban ali26-Aug-08 2:57 
Questionany way around the multiple Write problem? Pinmembertravislaborde24-Jan-06 16:03 
AnswerRe: any way around the multiple Write problem? PinmemberDaniel Fruzynski24-Jan-06 21:08 
GeneralRe: any way around the multiple Write problem? Pinmembertravislaborde25-Jan-06 0:52 
GeneralRe: any way around the multiple Write problem? PinmemberDaniel Fruzynski25-Jan-06 3:36 
AnswerRe: any way around the multiple Write problem? Pinmembertravislaborde26-Jan-06 2:46 
QuestionWhat about Performance? PinmemberAgeKay7-Feb-05 11:04 
AnswerRe: What about Performance? PinmemberSir Zooro8-Feb-05 8:56 
GeneralRe: What about Performance? PinmemberDanielHac8-Feb-05 14:27 
GeneralRe: What about Performance? PinmemberDavid S Hobbs8-Feb-05 23:31 
GeneralRe: What about Performance? PinmemberDanielHac9-Feb-05 1:19 
GeneralRe: What about Performance? PinmemberDavid S Hobbs9-Feb-05 7:59 
GeneralRe: What about Performance? PinmemberDanielHac9-Feb-05 8:10 
GeneralRe: What about Performance? PinmemberSimonGreen14-Feb-05 20:38 
GeneralRe: What about Performance? PinmemberSimonGreen14-Feb-05 20:41 
GeneralRe: What about Performance? PinmemberJeffster14-Sep-07 10:28 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140827.1 | Last Updated 7 Feb 2005
Article Copyright 2005 by Daniel Fruzynski
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid