![]() |
ReleaseRequestState Filter | |
| Home « Computers « DevBlog | ||
Back to: Development Blog Contents
Http Modules & ReleaseRequestState Filter
In March 2005 I had to find a way of performing string replacement in ASP.NET application web pages just before they were rendered. It was too tedious to change the existing code to perform the processing at page creation time, so I was hoping to find a blanket solution by hooking in somewhere after the pages had been composed and were about to be rendered by the browser.
Thanks to Tatham in the aus-dotnet mailing who sent me to a sample that showed how a Http Module could put a custom filter on the ReleaseRequestState event to do what I needed.
Add this to your Web.config file:
<httpModules> <add type="mycompany.myproject.MacroModule, mycompany.myproject" name="MacroModule" /> </httpModules> |
Following is a skeleton of the Http Module which processes the ReleaseRequestState event and passes each text response through a custom filter. Note that the Encoding is passed into the filter.
namespace mycompany.myproject public void Dispose()
{
HttpApplication application = HttpContext.Current.ApplicationInstance;
application.ReleaseRequestState -= new EventHandler(context_ReleaseRequestState);
} private void context_ReleaseRequestState(object sender, EventArgs e)
{
HttpResponse response = HttpContext.Current.Response;
if (string.Compare(response.ContentType,"text/html",true) == 0)
{
response.Filter = new MacroFilter(response.Filter,response.ContentEncoding);
}
}
}
}
|
This is the skeleton code of the custom filter, which is simply a facade over the original Stream that modifies the buffer that is being passed into the Write method. See the notes below.
namespace mycompany.myproject
{
internal class MacroFilter : Stream
{
private Stream s = null;
private Encoding enc = null;
private StringBuilder sb = null;
(-- method bodies omitted --) |
The class overrides and implements each abstract member of Stream (is there an easier way?). The middle methods in italics have the bodies omitted for brevity, but they just pass processing down to the original 's' Stream object.
In the Write method, a StringBuilder is constructed by encoding the bytes in the write buffer to a string. The comment indicates where the string can be modified as needed by your processing. The string will probably consist of mutiple text records delimited by CRLF or similar (don't make assumptions about the exact format). The bytes are then encoded back to bytes and written in place of the original ones.
This processing allows you to inspect and modify the raw buffer after it has been constructed by the application and before it is sent to the browser.
Some questions remain:
* How can we be sure the buffer will contain the entire page? The HttpResponse Buffer and BufferOutput properties control this, but it's not clear if or when the Write method might get a single page in arbitrary multiple buffer pieces, which could crash the sample code.
* Is there an easier way of coding the filter than using a raw Stream and overriding all the abstract methods?
* Why the ReleaseRequestState event? There are so many events, it would have taken me hours to find the right one without a hint up-front to save time.
Back to: Development Blog Contents