11

estoy usando la nueva System.Web.Optimization y han creado un paquete como este:paquetes system.web.optimization GZip

bundles.Add(New ScriptBundle("~/bundles/BaseJS").Include(
       "~/Resources/Core/Javascripts/jquery-1.7.1.js", 
       "~/Resources/Core/Javascripts/jquery-ui-1.8.16.js", 
       "~/Resources/Core/Javascripts/jquery.validate.js", 
       "~/Resources/Core/Javascripts/jquery.validate.unobtrusive.js", 
       "~/Resources/Core/Javascripts/jquery.unobtrusive-ajax.js")) 

y en mi opinión he añadido este

@System.Web.Optimization.Scripts.Render("~/bundles/BaseJS") 

En fiddler, la URL aparece con un encabezado caduca de 1 año en el futuro y un tipo de contenido de texto/javascript

En el web.config tengo un código para gzip que está trabajando en archivos JS estáticos pero no funciona t parece en los paquetes minificados.

<staticContent> 
    <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="365.00:00:00"/> 
    <remove fileExtension=".js"/> 
    <mimeMap fileExtension=".js" mimeType="text/javascript"/> 
</staticContent> 
<urlCompression doDynamicCompression="true" doStaticCompression="true" dynamicCompressionBeforeCache="true"/> 
<httpCompression directory="%SystemDrive%\inetpub\temp\IIS Temporary Compressed Files"> 
    <scheme name="gzip" dll="%Windir%\system32\inetsrv\gzip.dll"/> 
    <dynamicTypes> 
    <add mimeType="text/*" enabled="true"/> 
    <add mimeType="text/javascript" enabled="true"/> 
    </dynamicTypes> 
    <staticTypes> 
    <add mimeType="text/*" enabled="true"/> 
    <add mimeType="text/javascript" enabled="true"/> 
    </staticTypes> 
</httpCompression> 

¿Hay alguna manera de hacer que el paquete de procesamiento gzip contenga el contenido?

+0

creo que esto puede ser posible con un iBundleTransform pero no estoy seguro de cómo. https://twitter.com/ericdc1/status/219850852364599298 – ericdc

Respuesta

12

Como ha señalado, crear una transformación de paquete personalizada creando una clase que implemente IBundleTransform es el camino correcto. Por ejemplo, el siguiente es transformar un paquete de ejemplo que utiliza la SharpZipLib (via NuGet) hacer GZip compresión:

public class GZipTransform : IBundleTransform 
{ 
    string _contentType; 

    public GZipTransform(string contentType) 
    { 
     _contentType = contentType; 
    } 

    public void Process(BundleContext context, BundleResponse response) 
    { 
     var contentBytes = new UTF8Encoding().GetBytes(response.Content); 

     var outputStream = new MemoryStream(); 
     var gzipOutputStream = new GZipOutputStream(outputStream); 
     gzipOutputStream.Write(contentBytes, 0, contentBytes.Length); 

     var outputBytes = outputStream.GetBuffer(); 
     response.Content = Convert.ToBase64String(outputBytes); 


     // NOTE: this part is broken 
     context.HttpContext.Response.Headers["Content-Encoding"] = "gzip"; 
     response.ContentType = _contentType ; 
    } 
} 

Ahora, aquí está la parte desafortunada - en la prueba de esta muestra, he descubierto un error que va a evitar que se trabajando. El diseño original esperaba que la gente hiciera cosas bastante simples, y como tal, BundleResponse expone las propiedades que le permiten establecer el contenido (más específicamente, el contenido de la cadena) y el tipo de contenido. BundleContext expone una propiedad de HttpContext, que llevaría a una persona razonable a creer que las propiedades adicionales de una respuesta podrían establecerse allí (como se muestra arriba). Sin embargo, esto es engañoso por 2 razones:

  1. transforma Bundle se ejecutan como parte de la creación del paquete - y crear el paquete pasa la primera vez que se hace referencia (no eliminan las referencias, como en, el navegador sigue la atributo src en una etiqueta de script, pero a la que se hace referencia, como en, la vista llama al método Scripts.Render helper). En mi ejemplo anterior, esto significa que un encabezado de codificación de contenido con un valor de gzip se establecerá en la primera página con una vista que use los métodos auxiliares del agrupamiento para generar un enlace, y si el contenido HTTP real no está comprimido, usted Obtendré un error ya que el navegador no puede decodificar el contenido HTTP.

  2. Incluso si el # 1 no fuera un problema, el paquete se coloca inmediatamente en la memoria caché de ASP.NET después de haber sido creado, por lo que esta ruta de código solo se ejecutará una vez.

Estamos tomando una mirada al diseño de la próxima versión del marco que permite especificar todos los aspectos (idealmente) del mensaje de respuesta HTTP que está libre del contexto HTTP (lo que significa que es fácilmente cachable)

Una nota adicional. Para suministrar transformaciones de paquete personalizado, deberá recurrir a la creación de una instancia de Bundle en lugar de ScriptBundle/StyleBundle. Esas clases son realmente solo tipos de taquigrafía para paquetes con transformaciones de paquete preconfiguradas.Para crear un paquete basado en Bundle, que haría algo como lo siguiente:

var jqueryBundle = new Bundle("~/bundles/jqueryall", new GZipTransform("text/javascript")); 
jqueryBundle.Include("~/Scripts/jquery-1.*", 
    "~/Scripts/jquery-ui*", 
    "~/Scripts/jquery.unobtrusive*", 
    "~/Scripts/jquery.validate*"); 
bundles.Add(jqueryBundle); 
+4

Resulta que IIS Dynamic Content Compression hace esto sin toda la ceremonia. En mi caso, tuve que reiniciar IIS después de instalar DCC para hacerlo funcionar, por lo que se me indujo a pensar erróneamente que el sistema. La optimización de la red necesitaba intervención para gzip, pero no es así. – ericdc

+0

Usted escribe "Estamos examinando detenidamente el diseño en la próxima versión del marco ...", así que supongo que usted es miembro del equipo de ASP.NET. ¿Estás pensando en permitir el contenido de bytes en la próxima versión? Esto sería extremadamente útil para agrupar imágenes (sprites). – JohannesH

+2

¿Se arregló esto alguna vez en System.Web.Optimizations? Estoy en un entorno en el que no puedo usar la compresión IIS, por lo que esta parece ser la única forma viable que no sea utilizar un HttpModule. – kkara

5

Se puede lograr usando HttpModule

public class GzipModule : IHttpModule 
{ 
    #region IHttpModule Members 

    public void Init(HttpApplication application) 
    { 
     application.BeginRequest += Application_BeginRequest; 
    } 

    public void Dispose() 
    { 
    } 

    #endregion 

    private void Application_BeginRequest(Object source, EventArgs e) 
    { 
     HttpContext context = HttpContext.Current; 
     HttpRequest request = context.Request; 
     HttpResponse response = context.Response; 
     string acceptEncoding = request.Headers["Accept-Encoding"]; 

     if (String.IsNullOrEmpty(acceptEncoding)) 
      return; 

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

y registrarlo en config

<system.webServer> 
    <modules> 
     <add name="Gzip" type="Gecko.Web.GzipModule" /> 
    </modules> 
+2

Es cierto, pero ahora esto se ejecutará para TODAS las solicitudes, no simplemente para paquetes. –

11

Con el La última ASP.NET Optimization (v1.1.2), la clase GZipTransform no funciona bien.

He encontrado una nueva forma con una clase personalizada Bundle que siempre va a comprimir contenido de paquete (que se transformó y en caché) antes de la respuesta:

public class GZipBundle : Bundle 
{ 
    public GZipBundle(string virtualPath, params IBundleTransform[] transforms) 
     : base(virtualPath, null, transforms) { } 

    public override BundleResponse CacheLookup(BundleContext context) 
    { 
     if (null != context) GZipEncodePage(context.HttpContext); 
     return base.CacheLookup(context); 
    } 

    // Sets up the current page or handler to use GZip through a Response.Filter. 
    public static void GZipEncodePage(HttpContextBase httpContext) 
    { 
     if (null != httpContext && null != httpContext.Request && null != httpContext.Response 
      && (null == httpContext.Response.Filter 
      || !(httpContext.Response.Filter is GZipStream || httpContext.Response.Filter is DeflateStream))) 
     { 
      // Is GZip supported? 
      string acceptEncoding = httpContext.Request.Headers["Accept-Encoding"]; 
      if (null != acceptEncoding 
       && acceptEncoding.IndexOf(DecompressionMethods.GZip.ToString(), StringComparison.OrdinalIgnoreCase) >= 0) 
      { 
       httpContext.Response.Filter = new GZipStream(httpContext.Response.Filter, CompressionMode.Compress); 
       httpContext.Response.AddHeader("Content-Encoding", DecompressionMethods.GZip.ToString().ToLowerInvariant()); 
      } 
      else if (null != acceptEncoding 
       && acceptEncoding.IndexOf(DecompressionMethods.Deflate.ToString(), StringComparison.OrdinalIgnoreCase) >= 0) 
      { 
       httpContext.Response.Filter = new DeflateStream(httpContext.Response.Filter, CompressionMode.Compress); 
       httpContext.Response.AddHeader("Content-Encoding", DecompressionMethods.Deflate.ToString().ToLowerInvariant()); 
      } 

      // Allow proxy servers to cache encoded and unencoded versions separately 
      httpContext.Response.AppendHeader("Vary", "Content-Encoding"); 
     } 
    } 
} 

// Represents a bundle that does CSS minification and GZip compression. 
public sealed class GZipStyleBundle : GZipBundle 
{ 
    public GZipStyleBundle(string virtualPath, params IBundleTransform[] transforms) : base(virtualPath, transforms) { } 
} 

// Represents a bundle that does JS minification and GZip compression. 
public sealed class GZipScriptBundle : GZipBundle 
{ 
    public GZipScriptBundle(string virtualPath, params IBundleTransform[] transforms) 
     : base(virtualPath, transforms) 
    { 
     base.ConcatenationToken = ";" + Environment.NewLine; 
    } 
} 

continuación, puede utilizar GZipStyleBundle y GZipScriptBundle para reemplazar los Bundle clases originales : StyleBundle, ScriptBundle. Ej:

public static class BundleConfig 
{ 
    // For more information on Bundling, visit http://go.microsoft.com/fwlink/?LinkId=254725 
    public static void RegisterBundles(BundleCollection bundles) 
    { 
     bundles.Add(new GZipScriptBundle("~/bundles/jquery.js").Include(...)); 
     bundles.Add(new GZipScriptBundle("~/bundles/jquery-ui.js", new JsMinify()).Include(...)); 

     bundles.Add(new GZipStyleBundle("~/bundles/all.css", new CssMinify()).Include(...)); 
    } 
} 

Saludos