开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜