ASP.NET кэш и файловые зависимости - PullRequest
3 голосов
/ 30 апреля 2009

Я хочу, чтобы элемент кэша ASP.NET перерабатывался при прикосновении к конкретному файлу, но следующий код не работает:

                       HttpContext.Current.Cache.Insert(
                            "Key",
                            SomeObject,
                            new CacheDependency(Server.MapPath("SomeFile.txt")),
                            DateTime.MaxValue,
                            TimeSpan.Zero,
                            CacheItemPriority.High,
                            null);

«SomeFile.txt», кажется, не проверяется, когда я запускаю кеш, и его изменение не приводит к тому, что этот элемент становится недействительным.

Что я делаю не так?

Ответы [ 5 ]

5 голосов
/ 05 мая 2009

Проблема решена:

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

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

В двух словах:

public class Service 
{
        private static readonly Service _Instance = new Service();
        static Service () { }
        private Service () { }

        public static Service Instance
        {
            get { return _Instance; }
        }

        // The expensive data that this service exposes      
        private someObject _data = null;

        public someObject Data
        {
            get
            {
                 if (_data == null)
                     loadData();
                 return _data;
            }
        }


        private void loadData()
        {
            _data = GetFromCache();
            if (_data == null)
            {
                 // Get the data from our datasource
                 _data = ExpensiveDataSourceGet();

                 // Insert into Cache
                 HttpContext.Current.Cache.Insert(etc);
            }
        }
}

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

Cache.Insert имеет перегрузку, которая позволяет вам указывать обработчик события, для которого при удалении элемента кэша моим первым тестом было создание фиктивного обработчика и установка в нем точки останова. Как только я увидел, что кэш очищается, я понял, что «_data» не сбрасывается в ноль, поэтому следующий запрос к синглтону загрузил ленивое загруженное значение.

В некотором смысле я использовал двойное кэширование, хотя одноэлементный кэш был очень коротким, но достаточно длинным, чтобы раздражать.

Решение?

 HttpContext.Current.Cache.Insert(
     "Key",
      SomeObject,
      new CacheDependency(Server.MapPath("SomeFile.txt")),
      DateTime.MaxValue,
      TimeSpan.Zero,
      CacheItemPriority.High,
      delegate(string key, object value, CacheItemRemovedReason reason)
      {
          _data = null;
      }
 );

Когда очищается кеш, состояние в синглтоне также должно очищаться ... проблема решена.

Урок, полученный здесь? Не помещайте штат в одиночку.

1 голос
/ 30 апреля 2009

Работает ли ASP.NET под учетной записью с соответствующими разрешениями для файла, указанного в CacheDependency? Если нет, то это может быть одной из причин, почему CacheDependency не работает должным образом.

0 голосов
/ 05 мая 2009

Единственный способ воспроизвести это поведение - это если путь, предоставленный конструктору CacheDependency, не существует. CacheDependency не будет генерировать исключение, если путь не существует, поэтому он может быть немного обманчивым.

0 голосов
/ 30 апреля 2009

Ваш код выглядит хорошо для меня. Однако, помимо этого фрагмента, все может происходить.

  • Вы случайно вставляете каждый постбэк случайно?

  • Попробуйте сделать вашу зависимость кеша полем класса и проверять ее при каждой обратной передаче. Измените файл между ними и посмотрите, регистрируется ли он как «Измененный». e.g.:

    public partial class _Default : System.Web.UI.Page
    {
       CacheDependency dep;
    
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            dep = new CacheDependency(Server.MapPath("SomeFile.txt"));
            HttpContext.Current.Cache.Insert(
                        "Key",
                        new Object(),
                        dep,
                        DateTime.MaxValue,
                            TimeSpan.Zero, CacheItemPriority.High, null);
        }
    
    
        if (dep.HasChanged)
            Response.Write("changed!");
        else
            Response.Write("no change :(");   }}
    
0 голосов
/ 30 апреля 2009

Я думаю, вам нужно указать путь:

var d = new CacheDependency(Server.MapPath("SomeFile.txt"));

При необходимости добавьте ~\App_Data.

...