Cómo: Notificar a una aplicación cuando se quita un elemento de la caché

Actualización: noviembre 2007

En la mayoría de los escenarios de caché, cuando un elemento se elimina de la caché, no es necesario situarlo de nuevo en ella hasta que vuelva a ser necesario. El modelo de desarrollo típico es comprobar siempre la existencia del elemento en la caché antes de utilizarlo. Si el elemento ya se encuentra allí, puede utilizarlo. Si no es así, deberá recuperarlo y agregarlo de nuevo a la caché.

No obstante, en algunos casos es útil que se notifique a una aplicación cuando un elemento se elimina de la caché. Por ejemplo, en la caché podría haber un informe cuya creación consumiera un considerable tiempo de procesamiento. Cada vez que se elimine de la caché, conviene que se vuelva a generar y que se coloque inmediatamente de nuevo en la caché para que la próxima vez que se solicite, el usuario no tenga que esperar a que se procese.

Para habilitar la notificación de los elementos que se eliminan de la caché, ASP.NET proporciona el delegado CacheItemRemovedCallback. Este delegado define la firma que se debe utilizar al escribir un controlador de eventos al que se llama en respuesta a la eliminación de un elemento de la caché. ASP.NET también proporciona la enumeración CacheItemRemovedReason, que se utiliza para especificar el motivo de dicha eliminación.

Generalmente, la devolución de llamada se implementa creando un controlador en un objeto comercial que administre los datos concretos que se intentan recuperar de la caché. Por ejemplo, se podría utilizar un objeto ReportManager con dos métodos, GetReport y CacheReport. El método de informe GetReport comprueba la existencia del informe en la caché; si no está allí, el método vuelve a generar el informe y lo almacena en la caché. El método CacheReport tiene la misma firma de función que el delegado CacheItemRemovedCallback; cuando el informe se elimina de la caché, ASP.NET llama al método CacheReport, que lo vuelve a agregar a la caché.

Para notificar a una aplicación cuando se elimina un elemento de la caché

  1. Cree una clase que se encargue de recuperar el elemento de la caché y de controlar el método de devolución de llamada para agregarlo de nuevo.

  2. En la clase, cree un método que agregue un elemento a la caché.

  3. En la clase, cree un método que obtenga un elemento de la caché.

  4. Cree un método que controle la devolución de llamada de eliminación del elemento de la caché. Dicho método debe tener la misma firma de función que el delegado CacheItemRemovedCallback. En el método, defina la lógica que desea ejecutar cuando se elimine el elemento de la caché, es decir, la regeneración del elemento y su inmediata inclusión en la caché.

Para probar la devolución de llamada del elemento de caché

  1. Cree una página Web ASP.NET que llame al método de su clase que agrega el elemento a la caché.

    En el ejemplo de código siguiente se muestra cómo llamar al método GetReport de la clase ReportManager (definida en el ejemplo mostrado a continuación del procedimiento). A continuación, muestra el informe en un control Label denominado Label1 durante la ejecución del método Page_Load de la página.

    protected void Page_Load(object sender, EventArgs e)
    {
        this.Label1.Text = ReportManager.GetReport();
    }
    
    Protected Sub Page_Load(ByVal sender As Object, _
            ByVal e As System.EventArgs) Handles Me.Load
        Me.Label1.Text = ReportManager.GetReport()
    End Sub
    
  2. Solicite la página ASP.NET en un explorador y vea el informe.

    El informe se crea la primera vez que se solicita la página; las solicitudes posteriores tendrán acceso a él desde la caché hasta que sea eliminado de ésta.

Ejemplo

En el ejemplo de código siguiente se muestra una clase completa denominada ReportManager que controla la notificación cuando se elimina un elemento de la caché. La clase administra un informe con formato de cadena que representa un proceso de ejecución larga.

Aunque en el ejemplo se utiliza una clase declarada como static (Shared en Visual Basic), no es necesario emplear una clase estática. Sin embargo, el método que controlará la devolución de llamada debe existir cuando se elimine el elemento de la caché. Por ejemplo, no debería implementar el controlador de devolución de llamada en una página ASP.NET, ya que es posible que la página ya haya sido eliminada cuando el elemento se borre de la caché y, por consiguiente, el método para controlar la devolución de llamada no estará disponible. El uso de una clase estática para el método que controla la devolución de llamada garantiza que el método todavía existirá cuando se elimine el elemento de la caché. Sin embargo, la desventaja de una clase estática es que todos los métodos estáticos necesitan disponer de seguridad para la ejecución de subprocesos.

Precaución:

No establezca CacheItemRemovedCallback en un método de una página. Además de que el método de página no estará disponible para una devolución de llamada una vez que se elimine la página, señalar la devolución de llamada a un método de página puede impedir que la memoria utilizada por ésta sea reclamada por la recolección de elementos no utilizados. Esto sucede porque la devolución de llamada contiene una referencia a la página y el recolector de elementos no utilizados no eliminará un elemento de la memoria si éste tiene referencias. Durante los períodos de carga de la aplicación, esto podría ocasionar que la memoria se agote muy rápidamente.

La clase de ejemplo incluye estas características:

  • Un miembro privado para controlar si el informe se ha eliminado de la caché.

  • Un método denominado CacheReport que agrega un elemento a la caché bajo el nombre MyReport y establece que dicho elemento debe caducar un minuto después de que se agregue a la caché. El método también pasa el método ReportRemovedCallback al parámetro onRemoveCallback, que registra el método ReportRemoveCallback para que se le llame cuando el elemento se elimine de la caché.

  • Un método denominado GetReport que obtiene un elemento de la caché. Este método determina si el elemento denominado MyReport existe en la caché. Si no es así, llama a CacheReport, que se encarga de agregarlo a la caché.

  • Un método denominado ReportRemovedCallback que controla la devolución de llamada de eliminación del elemento de la caché. ReportRemovedCallback tiene la misma firma de función que el delegado CacheItemRemovedCallback. El método establece la variable _reportRemovedFromCache en true y, a continuación, agrega de nuevo el elemento a la caché a través del método CacheReport.

using System;
using System.Web;
using System.Web.Caching;
public static class ReportManager
{
    private static bool _reportRemovedFromCache = false;
    static ReportManager()
    { }

    public static String GetReport()
    {
        lock (typeof(ReportManager))
        {
            if (HttpContext.Current.Cache["MyReport"] != null)
                return (string)HttpRuntime.Cache["MyReport"];
            else
            {
                CacheReport();
                return (string)HttpRuntime.Cache["MyReport"];
            }
        }
    }

    public static void CacheReport()
    {
        lock (typeof(ReportManager))
        {
            HttpRuntime.Cache.Add("MyReport",
                CreateReport(), null, Cache.NoAbsoluteExpiration,
                new TimeSpan(0, 1, 0),
                System.Web.Caching.CacheItemPriority.Default,
                new CacheItemRemovedCallback(ReportRemovedCallback));
        }
    }

    private static string CreateReport()
    {
        System.Text.StringBuilder myReport = 
            new System.Text.StringBuilder();
        myReport.Append("Sales Report<br />");
        myReport.Append("2005 Q2 Figures<br />");
        myReport.Append("Sales NE Region - $2 million<br />");
        myReport.Append("Sales NW Region - $4.5 million<br />");
        myReport.Append("Report Generated: " + DateTime.Now.ToString() 
            + "<br />");
        myReport.Append("Report Removed From Cache: " + 
            _reportRemovedFromCache.ToString());
        return myReport.ToString();
    }

    public static void ReportRemovedCallback(String key, object value, 
        CacheItemRemovedReason removedReason)
    {
        _reportRemovedFromCache = true;
        CacheReport();
    }
}
Imports System
Imports System.Web
Imports System.Web.Caching
Public Class ReportManager
    Private Shared _reportRemovedFromCache As Boolean = False
    Shared Sub New()
    End Sub

    Private Sub New()
    End Sub

    Public Shared Function GetReport() As String
        SyncLock (GetType(ReportManager))
            If HttpContext.Current.Cache("MyReport") IsNot Nothing Then
                Return CStr(HttpRuntime.Cache("MyReport"))
            Else
                CacheReport()
                Return CStr(HttpRuntime.Cache("MyReport"))
            End If
        End SyncLock
    End Function

    Public Shared Sub CacheReport()
        SyncLock (GetType(ReportManager))
            HttpRuntime.Cache.Add("MyReport", CreateReport(), _
            Nothing, Cache.NoAbsoluteExpiration, New TimeSpan(0, 1, 0), _
            System.Web.Caching.CacheItemPriority.Default, _
            New CacheItemRemovedCallback(AddressOf ReportRemovedCallback))
        End SyncLock
    End Sub

    Private Shared Function CreateReport() As String
        Dim myReport As New System.Text.StringBuilder()
        myReport.Append("Sales Report<br />")
        myReport.Append("2005 Q2 Figures<br />")
        myReport.Append("Sales NE Region - $2 million<br />")
        myReport.Append("Sales NW Region - $4.5 million<br />")
        myReport.Append("Report Generated: " & _
            DateTime.Now.ToString() & "<br />")
        myReport.Append("Report Removed From Cache: " _
            & _reportRemovedFromCache.ToString())
        Return myReport.ToString()
    End Function

    Public Shared Sub ReportRemovedCallback(ByVal key As String, _
            ByVal value As Object, ByVal removedReason _
            As CacheItemRemovedReason)
        _reportRemovedFromCache = True
        CacheReport()
    End Sub
End Class

Vea también

Tareas

Cómo: Agregar elementos a caché

Cómo: Recuperar valores de elementos almacenados en caché

Cómo: Eliminar elementos de la caché en ASP.NET

Conceptos

Información general sobre el almacenamiento en caché en ASP.NET

Configuración de la caché en ASP.NET

Almacenar en caché datos de la aplicación