asp.net mvc сжимает поток и удаляет пробелы - PullRequest
9 голосов
/ 29 мая 2010

Итак, я сжимаю свой выходной поток через фильтр действий:

var response = filterContext.HttpContext.Response;
response.Filter = new DeflateStream(response.Filter), CompressionMode.Compress);

Который прекрасно работает. Теперь я также хотел бы удалить лишние пробелы, присутствующие. Я нашел http-модуль Мадса Кристенсена http://madskristensen.net/post/A-whitespace-removal-HTTP-module-for-ASPNET-20.aspx.

public class WhitespaceFilter : Stream {

    // using Mads Kristensen httpModule
    // http://madskristensen.net/post/A-whitespace-removal-HTTP-module-for-ASPNET-20.aspx

    private Stream os;
    private static Regex reg = new Regex(@"^\s+", RegexOptions.Multiline | RegexOptions.Compiled); 

    public WhitespaceFilter(Stream os) {
        this.os = os;
    }

    //methods that need to be overridden from stream
    public override bool CanRead {
        get { return true; }
    }

    public override bool CanSeek {
        get { return true; }
    }

    public override bool CanWrite {
        get { return true; }
    }

    public override void Flush() {
        os.Flush();
    }

    public override long Length {
        get { return 0; }
    }

    private long _position;
    public override long Position {
        get { return _position; }
        set { _position = value; }
    }

    public override int Read(byte[] buffer, int offset, int count) {
        return os.Read(buffer, offset, count);
    }

    public override long Seek(long offset, SeekOrigin origin) {
        return os.Seek(offset, origin);
    }

    public override void SetLength(long value) {
        os.SetLength(value);
    }

    public override void Close() {
        os.Close();
    }

    public override void Write(byte[] buffer, int offset, int count) {
        string html = System.Text.Encoding.Default.GetString(buffer);

        //remove whitespace
        html = reg.Replace(html, string.Empty);

        byte[] outdata = System.Text.Encoding.Default.GetBytes(html);

        //write bytes to stream
        os.Write(outdata, 0, outdata.GetLength(0));
    } 

Я добавил класс WhitespaceFilter и добавил новый фильтр, такой как сжатие:

var response = filterContext.HttpContext.Response;
response.Filter = new WhitepaperFilter(response.Filter);

Это тоже прекрасно работает. Тем не менее, у меня, похоже, проблемы с их объединением!

Я пытался:

var response = filterContext.HttpContext.Response;
response.Filter = new DeflateStream(new WhitespaceFilter(response.Filter), CompressionMode.Compress);

Однако это приводит к некоторым серьезным проблемам. HTML полностью запутался, и иногда я получаю ошибку 330.

Кажется, что метод записи фильтра Whitespace вызывается несколько раз. В первый раз строка html в порядке, но при последующих вызовах это просто случайные символы.

Я подумал, что это может быть из-за того, что поток был сдут, но разве фильтр пустых пространств не использует нетронутый поток, а затем передает результирующий поток вызову DeflateStream?

Есть идеи?

Ответы [ 2 ]

7 голосов
/ 29 декабря 2010

Для тех, кто зашел так далеко ... вы можете сделать это ... просто поменяйте местами последовательность цепочек потоков:

   public override void OnActionExecuting(ActionExecutingContext filterContext)
   {
        var response = filterContext.HttpContext.Response;

        // - COMPRESS
        HttpRequestBase request = filterContext.HttpContext.Request;
        string acceptEncoding = request.Headers["Accept-Encoding"];
        if (!String.IsNullOrEmpty(acceptEncoding))
        {
            acceptEncoding = acceptEncoding.ToUpperInvariant();

            if (acceptEncoding.Contains("GZIP"))
            {
                response.AppendHeader("Content-encoding", "gzip");
                response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
            }
            else if (acceptEncoding.Contains("DEFLATE"))
            {
                response.AppendHeader("Content-encoding", "deflate");
                response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
            }
        }

        // - REMOVE WHITE SPACE
        response.Filter = new WhitespaceFilter(response.Filter);
    }
0 голосов
/ 05 октября 2010

Я не вижу много неправильных в приведенном выше коде, однако вы можете попробовать этот подход:

var response = filterContext.HttpContext.Response; 
using(var wsf = new WhitespaceFilter(response.Filter))
{
   wsf.Flush();
   response.Filter = new DefalteStream(wsf, CompressMode.Compress);
}

Кстати, вы используете этот атрибутный подход при применении сжатия и удаления пробелов:

http://www.avantprime.com/articles/view-article/7/compress-httpresponse-for-your-controller-actions-using-attributes

DaTribe

...