Invalidar OutputCache en una aplicación MVC3


Ya sabemos que para activar el OutputCache  en MVC3, simplemente hay que decorar el Action Result que queramos con el ActionFilter OutputCache, por ejemplo:

[OutputCache(CacheProfile="Render")]
public ActionResult AllProducts()
{

Bien, esta configuración hará que el motor mvc busque la configuración del caché en el web config, en el que tendremos, por ejemplo, ésta:

<system.web>
   <caching>
      <outputCacheSettings>
         <outputCacheProfiles>
            <add name="Render" duration="3600" location="Any" />
         </outputCacheProfiles>
      </outputCacheSettings>
   </caching>
</system.web>
<system.webServer>
   <staticContent>
      <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="1.00:00:00"/>
   </staticContent>
   <caching>
      <profiles>
        <add extension=".swf" location="Any" duration="1.00:00:00" policy="CacheForTimePeriod" kernelCachePolicy="CacheForTimePeriod"/>
        <add extension=".css" location="Any" duration="1.00:00:00" policy="CacheForTimePeriod" kernelCachePolicy="CacheForTimePeriod"/>
        <add extension=".png" location="Any" duration="1.00:00:00" policy="CacheForTimePeriod" kernelCachePolicy="CacheForTimePeriod"/>
        <add extension=".gif" location="Any" duration="1.00:00:00" policy="CacheForTimePeriod" kernelCachePolicy="CacheForTimePeriod"/>
        <add extension=".jpg" location="Any" duration="1.00:00:00" policy="CacheForTimePeriod" kernelCachePolicy="CacheForTimePeriod"/>
        <add extension=".js" location="Any" duration="1.00:00:00" policy="CacheForTimePeriod" kernelCachePolicy="CacheForTimePeriod"/>
      </profiles>
   </caching>
</system.webServer>

Si modificamos el resultado a obtener en nuestro Action, es fácil que queramos invalidar el caché para que vuelva a cargar el contenido desde la base de datos y si además, nuestro contenido aparece en varios sitios del site, no nos valdrá con invalidar una URL relativa, acción que realizaríamos simplemente con:

HttpResponse.RemoveOutputCacheItem("/Products/AllProducts");

Si es el caso y queremos invalidar toda la caché, podemos hacerlo en una sola sentencia. Para ello, tenemos que crear una dependencia. Es decir, haremos que toda caché de todo ActionResult, dependan de un objeto, de este modo, al reiniciar dicho objeto, reniciaremos la caché dependiente.

Manos a la obra.

Primer punto, modificamos el global.asax para crear el objeto de caché con vida infinita (hasta que lo reiniciemos, como hemos dicho antes). Para ello, modificamos el método Application_Start y le añadimos la creación de dicho objeto:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    HttpContext.Current.Cache.Insert("Pages", DateTime.Now, null,
        System.DateTime.MaxValue, System.TimeSpan.Zero,
        System.Web.Caching.CacheItemPriority.NotRemovable,
        null);
    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
}

Segundo punto, creamos una clase que herede de ActionFilterAttribute para generar el Filtro:

public class CacheDependencyFilter : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            HttpContext.Current.Response.AddCacheItemDependency("Pages");
        }
    }

Tercer punto, modificamos el global.asax para añadir el filtro creado y que la dependencia se genere cada vez que se ejecuta un Action. Para ello, modificamos el método RegisterGlobalFilters:

public void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new HandleErrorAttribute());
    filters.Add(new CacheDependencyFilter());
}

Con esto ya tenemos nuestra infraestructura creada. Lo último que nos quedaría por hacer, es un método que nos sirva para reiniciar (invalidar) el caché. Para ello, podemos, por ejemplo crear una clase con un método estático que realice dicho cometido:

public class CacheFactory
{
    public static void InvalidateCache()
    {
        HttpContext.Current.Cache.Insert("Pages", DateTime.Now, null,
            System.DateTime.MaxValue, System.TimeSpan.Zero,
            System.Web.Caching.CacheItemPriority.NotRemovable,
            null);
    }
}

De este modo, en cualquier punto de nuestra aplicación, podremos invalidar el caché simplemente invocando a:

CacheFactory.InvalidateCache();

Y bien, esto es todo por hoy.

Google
Visita mi perfil en Google Plus

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s