ASP.NET Response Filter to Transform Displayed Output of ASPX Pages?
I created a simple HttpModule and response stream to reformat the rendered output of web pages (see code snippets below).
In the HttpModule, I set the Response.Filter to my PageStream:
m_Application.Context.Response.Filter = new PageStream(m_Application.Context);
In PageStream, I overwrite the Write method to reformat the output:
public override void Write(byte[] buffer, int offset, int count)
{
string html = System.Text.Encoding.UTF8.GetString(buffer);
//Do some string resplace operations here...
byte[] input = System.Text.Encoding.UTF8.GetBytes(html);
m_DefaultStream.Write(input, 0, input.Length);
}
And it works great when using it on simple HTML pages (.html), but when I use this method on ASPX pages (.aspx), the Write method gets called multiple times, splitting the reformat into different steps and potentially killing the string replace operations.
How can I solve this? Is there a way to prevent the ASPX page from calling Write multiple times, eg. changing the size of my buffer, or have I completely taken the wrong approach using this Response.Filter method to handle the output being output?
source to share
Guided by an article suggested by Darin Dimitrov, I ended up with the following implementation of the Write method, which also works great with ASPX pages:
public override void Write(byte[] buffer, int offset, int count)
{
string strBuffer = System.Text.UTF8Encoding.UTF8.GetString (buffer, offset, count);
if (!strBuffer.Contains("</html>"))
{
m_ResponseHtml.Append(strBuffer);
}
else
{
m_ResponseHtml.Append(strBuffer);
string html = m_ResponseHtml.ToString ();
//Do some string operations here...
byte[] input = System.Text.Encoding.UTF8.GetBytes(html);
m_DefaultStream.Write(input, 0, input.Length);
}
}
The code uses StringBuilder (m_ResponseHtml) to accumulate all the HTML before executing the actual manupulation line on the output output.
source to share
I will just buffer the data in the Write method and perform string operations in the Close method, like this:
private readonly Stream _forwardStream;
private readonly StringBuilder _sb;
// snip
public override void Write (byte[] buffer, int offset, int count)
{
string chunk = Encoding.UTF8.GetString (buffer, offset, count);
_sb.Append (chunk);
}
public override void Close ()
{
string result = GetManipulatedString ();
byte[] rawResult = Encoding.UTF8.GetBytes (result);
_forwardStream.Write (rawResult, 0, rawResult.Length);
base.Close ();
_forwardStream.Close ();
}
(It might even be better if you are collecting data in a MemoryStream)
source to share
You may need to check the content type before attaching a response filter:
var response = m_Application.Context.Response;
if (response.ContentType == "text/html")
{
response.Filter = new PageStream(m_Application.Context);
}
There's also a nice article describing response filters in ASP.NET.
source to share