FilterAttributes conflicting Compress, RegexFilter
I have a controller action like so
[AcceptVerbs(HttpVerbs.Get | HttpVerbs.Put)]
[InsertScript(Order = 1)]
[Compress(Order = 2)]
public ViewResult Service(Page page) { //omitted }
The InsertScript attribute applied a Response.Filter
response.Filter = new RegexResponseFilter(response.Filter, scriptInsertRegex, replacementString);
The regex response filter is based on a blog post here. Note I am not trying to remove whitespace I'm trying to insert a scrip tag but that is irrelevant.
The write method of the RegexResponseFilter is as so. The rest is the same as the blogpost.
public override void Write(byte[] buffer, int offset, int count)
{
// capture the data and convert to string
var data = new byte[count];
Buffer.BlockCopy(buffer, offset, data, 0, count);
// filter the string
var s = Encoding.Default.GetString(buffer);
s = regex.Replace(s, replacement);
// write the data to stream
var outdata = Encoding.Default.GetBytes(s);
response.Write(outdata, 0, outdata.GetLength(0));
}
This works great in isolation. But when I applied a compression attribute (fairly standard one seen in any number of places on the internets), the thing broke with FF4 giving the error message.
The page you are trying to view cannot be shown because it uses an invalid or un开发者_如何学运维supported form of compression.
I smelled a red herring and removed the InsertScript attribute and it works. So the two are conflicting in some way. Here is the compression attribute for completeness.
public class CompressAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//get request and response
var request = filterContext.HttpContext.Request;
var response = filterContext.HttpContext.Response;
//get encoding
var encoding = request.Headers["Accept-Encoding"];
if (string.IsNullOrWhiteSpace(encoding))
return;
encoding = encoding.ToUpperInvariant();
if (encoding.Contains("DEFLATE") || encoding == "*")
{
response.AppendHeader("Content-encoding", "deflate");
response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
}
else if (encoding.Contains("GZIP"))
{
response.AppendHeader("Content-encoding", "gzip");
response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
}
base.OnActionExecuting(filterContext);
}
}
It's probably something obvious but this looks like it should work. The insert should get applied before the compression takes place.
Many thanks
Try flipping the order of inclusion:
[AcceptVerbs(HttpVerbs.Get | HttpVerbs.Put)]
[Compress(Order = 1)]
[InsertScript(Order = 2)]
public ViewResult Service(Page page) { //omitted }
Another possibility is to combine multiple filters like this and then use a single action filter attribute:
response.Filter = new CompressStream(new InsertScript(response.Filter));
For this to work you need to write a custom CompressStream
class the same way you did with the InsertScript
and then have a single action filter attribute which will combine the two streams.
精彩评论