martes, 20 de octubre de 2015
Está claro que uno de los secretos para la creación de aplicaciones web de alto rendimiento es el uso apropiado del caché, y por esta razón todos los frameworks incorporan herramientas que hacen posible almacenar información que pueda ser reutilizadas para acelerar la respuesta de peticiones posteriores, como porciones de página o resultados de procesos costosos.
En ASP.NET 4.x y anteriores, siempre podíamos acceder a objeto
Pero antes de continuar, un par de avisos:
Veamos un ejemplo de la forma más simple que tenemos de utilizar este tag helper en una vista:
Otro aspecto a destacar es que hemos especificado el valor del parámetro
Si accedemos a esta vista y refrescamos la página segundos más tarde, el resultado que tendremos es el siguiente. Como podemos ver, el bloque del interior de
Otro ejemplo. En este caso, la primera ejecución de la página durará cinco segundos, pero tras ella todas las demás retornarán inmediatamente el contenido cacheado sin necesidad de ejecutar nada:
Ah, y una última cosa: al menos de momento,
Publicado en Variable not found.
En ASP.NET 4.x y anteriores, siempre podíamos acceder a objeto
Cache
disponible en el contexto de la petición, o a los componentes presentes en System.Web.Caching
y crear nuestras soluciones personalizadas, pero realmente MVC no aportaba más ayudas de serie que el filtro [OutputCache]
. Su objetivo era cachear el resultado de acciones durante un tiempo determinado y reutilizarlo en peticiones siguientes, lo que era suficiente para muchos escenarios pero complicaba un poco otras necesidades comunes, como el cacheo de porciones de páginas.Pero antes de continuar, un par de avisos:
- Si aún no sabes lo que es un tag helper, ya estás tardando en leer este post ;)
- ASP.NET se encuentra aún en desarrollo, por lo que parte de lo expuesto a continuación podría variar en la versión final del producto.
<cache>
. El resultado de renderizar su contenido será cacheado en el servidor y reutilizado las siguientes ejecuciones de la vista, hasta que la caché expire por las condiciones que hayamos indicado.Veamos un ejemplo de la forma más simple que tenemos de utilizar este tag helper en una vista:
<h2>Current: @DateTime.Now.ToString("hh:mm:ss"))</h2> <cache expires-after="TimeSpan.FromSeconds(30)"> <h2>Cached: @DateTime.Now.ToString("hh:mm:ss")</h2> </cache>Hay varios aspectos interesantes en este código. Primero, observad que este tag helper define una etiqueta nueva, a diferencia de otros que hemos visto, como
AnchorTagHelper
para construir enlaces <a>
. Debido a ello, no hay necesidad de distinguir sus parámetros con un prefijo, como los habituales "asp-" que vemos en otros tag helpers que modifican etiquetas existentes.Otro aspecto a destacar es que hemos especificado el valor del parámetro
expires-after
directamente mediante una expresión C#, sin necesidad de utilizar el carácter de escape "@" de Razor. Esto es así porque el parser ha detectado que la propiedad subyacente es de tipo TimeSpan
, por lo que directamente espera que codifiquemos ahí una expresión de este tipo, y el entorno puede ayudarnos con el imprescindible intellisense.Si accedemos a esta vista y refrescamos la página segundos más tarde, el resultado que tendremos es el siguiente. Como podemos ver, el bloque del interior de
<cache>
no será evaluado de nuevo hasta pasados los 30 segundos que hemos indicado en el parámetro expires-after
, retornando en su lugar el resultado que fue cacheado anteriormente:
Ejecución inicial
|
Tras refrescar la página
|
Otro ejemplo. En este caso, la primera ejecución de la página durará cinco segundos, pero tras ella todas las demás retornarán inmediatamente el contenido cacheado sin necesidad de ejecutar nada:
<cache expires-after="TimeSpan.FromMinutes(10)"> @{ await Task.Delay(5000); } <h2>Cached: @DateTime.Now.ToString("hh:mm:ss")</h2> </cache>La etiqueta
<cache>
tiene parámetros que permiten configurar su comportamiento de forma muy similar al filtro [OutputCache]
, y que seguro que os son familiares:- Parámetros para indicar la duración del caché:
expires-after
, visto anteriormente en los ejemplos, indica el tiempo de validez del caché desde que se almacena su contenido.expires-sliding
, contiene unTimeSpan
que indica el tiempo en que el caché caducará tras haber accedido a su contenido por última vez.expires-on
, un valorDateTimeOffset
que indica en términos absolutos cuándo expirará el contenido cacheado.
<cache expires-sliding="TimeSpan.FromSeconds(30)"> <h2>Cached: @DateTime.Now.ToString("hh:mm:ss")</h2> </cache>
- Parámetros que indican qué factores actúan como criterios de discriminación a la hora de salvar o recuperar valores de la caché. Esto es bastante útil si queremos cachear porciones de página para determinado grupo de usuarios o peticiones:
var-by
, permite que el caché varíe dependiendo del valor alfanumérico arbitrario del mismo.var-by-header
, nombre del encabezado HTTP que variará el caché.var-by-query
, una lista de parámetros del query string, separados por comas, que actuarán como discriminador.
<cache expires-after="TimeSpan.FromMinutes(10)" var-by-query="searchTerm"> <h2>Search results:</h2> <ul> @foreach(var product in Products) { <li>@product.Name<li> } </ul> </cache>
var-by-route
, una lista de parámetros de ruta que actuarán como discriminador.var-by-cookie
, lista de nombres de cookies separados por comas, que actuarán como disvar-by-user
, un booleano que indica si el valor de la caché debe variar en función de la identidad del usuario conectado.
<cache expires-after="TimeSpan.FromMinutes(10)" var-by-user="true"> <h2>Hello, @User.Identity.Name </h2> </cache>
- Parámetros generales de comportamiento:
priority
, un valorCacheItemPriority
que indica la prioridad del contenido en situaciones de escasa memoria.enabled
, que si establecemos a "false" permite desactivar el caché, forzando a que se procese el contenido del tag<cache>
como si no existiera. Esto puede ser útil, por ejemplo, para depurar una página:
<cache expires-after="TimeSpan.FromMinutes(10)" enabled="false"> <h2>Cached: @DateTime.Now.ToString("hh:mm:ss")</h2> </cache>
vary-by-cookie
, vary-by-query
o vary-by-route
.Ah, y una última cosa: al menos de momento,
CacheTagHelper
usa internamente para almacenar el caché una instancia de IMemoryCache
, por lo que el contenido no puede ser distribuido o enviado a un almacenamiento externo como Redis o SQL Server, ni será persistente si el servidor sufre algún tropezón.Publicado en Variable not found.
3 Comentarios:
Hola José, que gran post y que claro! Ahora me surge una duda, cuando usamos expires-after y expires-sliding en el mismo tag helper, cual tiene prioridad en caso que se "sobre ponga" el momento en que debe vencer el caché?
Saludos!
Hola, Julio!
A día de hoy, si en el mismo helper se indican ambos parámetros, expires-after ganaría pues indica la caducidad en términos absolutos del contenido.
Saludos & gracias por comentar!
Gracias José, eso mismo pensé, pero mejor estar seguros, seriá interesante que más adelante se incluya la posiblidad de usar componentes externos para guardar dicha caché como Redis, SQL u otros... aunque claro, esto es Open Soure, siempre es posible hacer un PR :)
Saludos!
Enviar un nuevo comentario