In the project we needed to modify the response that is generated by the ASP.NET pages/web-services/doesn't-matter-what. If you search for the best approach to do this, it's to create a HttpModule and there add your own stream to Response.Filter. It gives you an incoming stream and you write your own modified stream. All well and nice. An example of this advice is here.
If you're serving mostly text content, it's quite useful and important to use compression capabilities that servers and browsers had for years. In terms of IIS and the kind of pages/web-services that I mentioned, that would be Dynamic Compression. Nice. It works by itself too. Got it working for those additionally processed requests from (1) too.
Here's the fun though: instead of the text content the filter stream from (1) now recieves gzipped bytes in the incoming stream that it's supposed to transform. Whoops. The order of things is definitely wrong. Text things should be processed first and then gzipped.
My first guess was I should get the custom HttpModule fire before the DynamicCompressionModule. There is an ordering of modules per-application indeed, although I had to remove locks from the native modules on the server level first. It didn't help. Spent some times researching and looking at FREBs.
Turns out what's important is the pipeline. Described here. Dynamic compression module does its job on RELEASE_REQUEST_STATE. So does the custom module. But it doesn't matter. The custom module doesn't actually perform the transformation when it's running that event. It sets the Response.Filter. When does the filter fire? Some more digging and debugging, it's fired during the run of AspNetFilterModule.
You won't see AspNetFilterModule in IIS settings though. Where you'll see it is the source code of HttpApplication. It's a pseudo-module that is added by ASP.NET itself to run the filters chain. And it's subscribed to... UPDATE_REQUEST_CACHE notification. That goes after the RELEASE_REQUEST_STATE. No matter how you order the modules, it will be after the compression.
So it's impossible to have a text post-processing with Response.Filter AND use the standard DynamicCompressionModule at the same time. This is where I'm seeking help. Did nobody have this scenario? It feels common.
Is there a way to transform the text output in the HttpModule without using Response.Filter? Preferably right when the module is executed on the RELEASE_REQUEST_STATE event. The Response.OutputStream is available, but it's write-only and there's no obvious way to read the current output stream that I see.