Практическое руководство. Уведомление приложения об удалении элемента из кэша

Visual Studio 2010

Обновлен: Ноябрь 2007

В большинстве сценариев при удалении элемента из кэша нет необходимости помещать его обратно в кэш, пока он не потребуется снова. Обычно при разработке всегда проверяется наличие элемента в кэше перед его использованием. Если элемент находится в кэше, то его можно использовать. Если элемента нет в кэше, он повторно извлекается и добавляется в кэш.

Однако в некоторых случаях полезно уведомлять приложение при удалении элемента из кэша. Например, используется кэшированный отчет, на создание которого требуется значительное время. При его удалении из кэша необходимо создать его заново и незамедлительно поместить в кэш, чтобы при его следующем запросе пользователю не пришлось ждать.

Чтобы включить уведомление об удалении элементов из кэша, ASP.NET предоставляет делегат CacheItemRemovedCallback. Делегат определяет сигнатуру, используемую при написании обработчика событий, который вызывается в ответ на удаление элемента из кэша. ASP.NET также предоставляет перечисление CacheItemRemovedReason, используемое для указания причины удаления элемента кэша.

Как правило обратный вызов реализуется в результате создания обработчика бизнес-объектов, управляющего определенными данными кэша, которые следует извлечь. Например, используется объект ReportManager с двумя методами GetReport и CacheReport. Метод отчета GetReport проверяет кэш и определяет, было ли уже выполнено кэширование отчета. Если нет, то метод повторно формирует отчет и кэширует его. Метод CacheReport имеет такую же сигнатуру функции делегата CacheItemRemovedCallback. При удалении отчета из кэша ASP.NET вызывает метод CacheReport, который повторно добавляет его в кэш.

Уведомление приложения об удалении элемента из кэша

  1. Создайте класс, отвечающий за извлечение элемента из кэша и обработку метода обратного вызова для добавления элемента обратно в кэш.

  2. В классе создайте метод, который добавляет элемент в кэш.

  3. В классе создайте метод, который извлекает элемент из кэша.

  4. Создайте метод, обрабатывающий обратный вызов удаления элемента кэша. Этот метод должен иметь ту же сигнатуру функции, что и делегат CacheItemRemovedCallback. В методе выполните логику, которую требуется запустить при удалении элемента из кэша (например, логику повторного создания элемента и добавления его обратно в кэш).

Тестирование обратного вызова элемента кэша

  1. Создайте веб-страницу ASP.NET, вызывающую метод в классе, который добавляет элемент в кэш.

    В следующем примере кода проиллюстрирован вызов метода GetReport класса ReportManager (определенный в примере после описания процедуры). Затем отображается отчет в элементе управления Label с именем Label1 во время выполнения метода Page_Load страницы.

    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. Выполните запрос страницы ASP.NET в обозревателе и просмотрите отчет.

    Отчет создается при первом запросе страницы, а последующие запросы будут получать доступ к отчету из кэша, пока он не будет удален.

В следующем примере показан полный класс с именем ReportManager, который обрабатывает уведомление при удалении элемента из кэша. Класс управляет отчетом в виде строки, представляющей длительный процесс.

Хотя в примере используется класс, объявленный как static (Shared в Visual Basic), статический класс использовать необязательно. Однако метод, обрабатывающий ответный вызов, должен существовать при удалении элемента кэша. Например, не следует реализовывать обработчик обратного вызова на странице ASP.NET, поскольку страница может быть удалена ко времени удаления элемента из кэша и, следовательно, метод обработки обратного вызова будет недоступен. Использование статического класса для метода обработки обратного вызова гарантирует, что метод будет по-прежнему существовать при удалении элемента из кэша. Однако недостатком статического класса является то, что все статические методы должны быть потокобезопасными.

7kxdx246.alert_caution(ru-ru,VS.100).gifВнимание!

Не указывайте метод в качестве значения CacheItemRemovedCallback на странице. Кроме того, что метод страницы может оказаться недоступен для обратного вызова после удаления страницы; направление обратного вызова к методу страницы может помешать средству сборки мусора высвободить память, используемую страницей. Это происходит, поскольку обратный вызов содержит ссылку на страницу и средство сборки мусора не удаляет элемент из памяти, если на элемент существуют ссылки. Во время загрузки приложения это может привести к очень быстрому заполнению свободной памяти.

Пример класса включает следующие возможности:

  • Закрытый член для отслеживания удаления отчет из кэша.

  • Метод с именем CacheReport, добавляющий элемент в кэш под именем MyReport и задающий истечение срока действия элемент через одну минуту, после добавления его в кэш. Этот метод также передает метод ReportRemovedCallback параметру onRemoveCallback, который регистрирует метод ReportRemoveCallback таким образом, чтобы он вызывался при удалении элемента из кэша.

  • Метод с именем GetReport, извлекающий элемент из кэша. Этот метод определяет наличие в кэше элемента с именем MyReport. Если элемент не существует, то метод вызывает CacheReport,, который добавляет элемент в кэш.

  • Метод с именем ReportRemovedCallback, обрабатывающий обратный вызов удаления элемента из кэша. ReportRemovedCallback имеет ту же сигнатуру функции, что и делегат CacheItemRemovedCallback. Метод присваивает переменной _reportRemovedFromCache значение true и добавляет элемент обратно в кэш с помощью метода 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();
    }
}
Показ: