2010-05-29 22 views
9

Więc ja ściskając moją strumienia wyjściowego za pomocą filtra Działanie:asp.net mvc strumień kompres i usuń spacje

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

który działa świetnie. Teraz chciałbym również usunąć nadmiar białych znaków. Znalazłem moduł http Mads Kristensen: 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)); 
    } 

dodałem klasę WhitespaceFilter i dodano nowy filtr jak kompresji:

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

To również działa świetnie. Jednak wydaje mi się, że mam problemy z łączeniem tych dwóch!

Próbowałem:

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

Jednak prowadzi to w niektórych ważnych kwestiach. HTML jest całkowicie pomieszany, a czasami pojawia się błąd 330.

Wygląda na to, że metoda zapisu filtra w przestrzeni białej jest wywoływana wiele razy. Za pierwszym razem ciąg html jest w porządku, ale przy kolejnych wywołaniach jest po prostu losowymi znakami.

Pomyślałem, że może to być spowodowane tym, że strumień został odrzucony, ale nie jest filtrem białych znaków wykorzystującym nietknięty strumień, a następnie przekazującym wynikowy strumień do wywołania DeflateStream?

Wszelkie pomysły?

+4

Po co go usuwać, jeśli zamierzasz go skompresować? Martwiłbym się tylko, gdy dostarczałem wyniki bez kompresji. Białe spacje naprawdę dobrze się kompresują. – tvanfosson

+2

Fiddler pokazuje, że z usuniętą białą przestrzenią rozmiar pliku jest nieco mniejszy, jednak w rzeczywistym projekcie masz rację; różnica byłaby znikoma. Po prostu interesuje mnie, dlaczego to nie działa, kiedy wydaje się, że powinno. –

+0

Zobacz wyniki tego gościa, jeśli skompresujesz i usuniesz białe spacje: http://stackoverflow.com/questions/855526/removing-extra-whitespace-from-generated-html-in-mvc – eadam

Odpowiedz

7

Dla tych, którzy się tak daleko ... można to zrobić ... po prostu zamienić kolejność strumieniu łańcuchowanie:

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); 
    } 
+5

Zrobiłem test z wydajnością. Przycinanie białych znaków w czasie wykonywania jest okropne. Od 200 rps spadł do 20 rps. – BrunoLM

0

Nie widzę wiele złego w powyższym kodzie jednak może chcesz spróbować tego podejścia:

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

BTW używasz tego podejścia atrybutu przy stosowaniu kompresji i białej przestrzeni usuwanie:

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

DaTribe