Please help me with this action filter.
I think i need to use OnResultExecuted method
How can i have access to otput html and replace something in them?
thank you.
Please help me with this action filter.
I think i need to use OnResultExecuted method
How can i have access to otput html and replace something in them?
thank you.
Now I see what you want to do. And I think I might have a solution. I have used parts of this approach in a output cache solution a while back, so I think it will work.
First you need your own stream class that looks like this:
private class CapturingResponseFilter : Stream
{
private readonly Stream _sink;
private readonly MemoryStream _mem;
public CapturingResponseFilter(Stream sink)
{
_sink = sink;
_mem = new MemoryStream();
}
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return false; }
}
public override long Length
{
get { return 0; }
}
public override long Position { get; set; }
public override long Seek(long offset, SeekOrigin direction)
{
return 0;
}
public override void SetLength(long length)
{
_sink.SetLength(length);
}
public override void Close()
{
_sink.Close();
_mem.Close();
}
public override void Flush()
{
_sink.Flush();
}
public override int Read(byte[] buffer, int offset, int count)
{
return _sink.Read(buffer, offset, count);
}
public override void Write(byte[] buffer, int offset, int count)
{
_mem.Write(buffer, 0, count);
}
public string GetContents(Encoding enc)
{
var buffer = new byte[_mem.Length];
_mem.Position = 0;
_mem.Read(buffer, 0, buffer.Length);
return enc.GetString(buffer, 0, buffer.Length);
}
}
And then you do something like this in your action filter:
private Stream _originalOutputStream;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
_originalOutputStream = filterContext.HttpContext.Response.Filter;
filterContext.HttpContext.Response.Flush();
filterContext.HttpContext.Response.Filter = new CapturingResponseFilter(filterContext.HttpContext.Response.Filter);
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
if (_originalOutputStream == null) return;
filterContext.HttpContext.Response.Flush();
var capturingResponseFilter = (CapturingResponseFilter)filterContext.HttpContext.Response.Filter;
filterContext.HttpContext.Response.Filter = _originalOutputStream;
var textWritten = capturingResponseFilter.GetContents(filterContext.HttpContext.Response.ContentEncoding);
//Do what you want with your text (textWritten).
filterContext.HttpContext.Response.Write(textWritten);
}
I would consider it a little bit of a hack solution. But I haven't seen anything that isn't.
How about using a whitespace removal HTTP module? It's simple to implement, clean and reusable...
http://madskristensen.net/post/A-whitespace-removal-HTTP-module-for-ASPNET-20.aspx
As with any generic whitespace removal solution though, it can easily introduce errors by removing white space where it is required. It wouldn't take long to give it a try though. :-)
Edited after comments
This will not work with .aspx files out of the box so you'll need to change the context_BeginRequest to the following...
void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication app = sender as HttpApplication;
if (app.Response.ContentType == "text/html"
|| app.Response.ContentType == "application/xhtml+xml")
{
app.Response.Filter = new WhitespaceFilter(app.Response.Filter);
}
}
I would like to extend Russel's solution. In MVC or i guess everywhere in beginrequest event the Response.ContentType is "text/html" since we don't know what we will answer. I founf another event where the content is defined and the filter is applyable: PostReleaseRequestState