Caching de bundles en MVC 4 (o MVC 3, o Webforms…)

Hace unos meses ya estuvimos comentando el interesante paquete System.Web.Optimizations que se distribuía con la developer preview de MVC 4, aunque también decíamos que este paquete era igualmente descargable a través de Nuget, y esto hacía posible su uso con MVC 3 o incluso con WebForms.


Como vimos en su momento, su uso era bastante sencillo. En resumidas cuentas, si no queríamos complicarnos demasiado la vida, era suficiente con introducir el siguiente código en la inicialización de la página (en el Application_Start del Global.asax):
    BundleTable.Bundles.RegisterTemplateBundles();
(Bueno, en la preview el método a llamar era EnableDefaultBundles(), pero el resultado era el mismo)

Simplemente con ello, ya podíamos acceder a dos recursos que eran generados automáticamente por el sistema:
  • /scripts/js, que contiene un único archivo .js con todos los scripts existentes en la carpeta /scripts del proyecto, convenientemente minimizados.
  • /content/css, donde encontramos en un único archivo todos los .css presentes en /content, también minimizados para aligerar su descarga.
  • /content/themes/base/css, nuevo en la última versión del componente, que incluye los estilos relativos al tema básico de jQuery UI, utilizado en la plantilla del proyectos de MVC 4.
Además de las ventajas que ofrece en tiempo de ejecución, este mecanismo es muy cómodo a la hora de mantener los scripts actualizados con Nuget. Es decir, dado que descargamos todos los scripts en una única llamada y bajo una única denominación, ya no será necesario andar actualizando las referencias a las bibliotecas en el _Layout.cshtml, algo que resulta molestillo en estos momentos cada vez que actualizamos.

Con la beta de MVC 4 recientemente liberada, este componente ha incluido también un interesante sistema de cacheo que hace aún más eficiente y automático su uso. Si observamos el layout de la plantilla de proyectos ASP.NET MVC 4 veremos que incluye las siguientes líneas:
<link href="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/Content/css")" 
      rel="stylesheet" type="text/css" />
<link href="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/Content/themes/base/css")" 
      rel="stylesheet" type="text/css" />
<script src="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/Scripts/js")">
</script>
Observad que las referencias a los distintos recursos se generan a través del método ResolveBundleUrl(). Pues bien, el código generado por las líneas anteriores es, más o menos así de sorprendente:

<link href="/Content/css?v=oI5uNwN5NWmYrn8EXEybCIbINNBbTM_DnIdXDUL5RwE1" 
      rel="stylesheet" type="text/css" />
<link href="/Content/themes/base/css?v=UM624qf1uFt8dYtiIV9PCmYhsyeewBIwY4Ob0i8OdW81" 
      rel="stylesheet" type="text/css" />
<script src="/Scripts/js?v=GP89PKpk2iEmdQxZTRyBnKWSLjO7XdNG4QC1rv6LPxw1"></script>
En las referencias se está añadiendo un parámetro que contiene un valor hash correspondiente al contenido de la carpeta empaquetada en el momento de generación de la vista. La primera petición que se realice enviará de vuelta los recursos empaquetados y minimizados con una validez a nivel de caché de un año; las siguientes peticiones, por tanto, se resolverán muy rápidamente mediante un HTTP 304 (No modificado):

Respuestas HTTP 304 en peticiones

A partir de ahí, cualquier cambio que se realice en alguno de los archivos o directorios incluidos en los bundles provocará un cambio de hash, por lo que la petición será diferente y, por tanto, el resultado no se tomará desde la caché.

Publicado en: Variable not found.
Published 23/4/2012 17:52 por José M. Aguilar
Comparte este post:
http://geeks.ms/blogs/jmaguilar/archive/2012/04/23/caching-de-bundles-en-mvc-4-o-mvc-3-o-webforms.aspx