0

I would like to store a small list of objects and create a dependency to the website's start page. Thus enforcing cache invalidation when the start page is altered. This was easily done with the old cache implementation, which now is deprecated.

The documentation says I should be using the CacheEvictionPolicy class. But I can't figure out how to setup dependencies with this class.

My question is: How do one cache objects with dependencies to EPiServer content (IContent) in EPiServer 7.5 (without using deprecated methods and including the feature of invalidation messages between web servers)?

maets
  • 750
  • 6
  • 18

2 Answers2

2

You should be able to use DataFactoryCache.CreateDependency() to create cache dependencies. It supports specifying a ContentReference as its parameter, for example ContentReference.StartPage to clear a cache entry when the start page is updated.

Also, much of this (albeit for EPiServer 6) is still valid: http://tedgustaf.com/blog/2010/5/cache-objects-in-episerver-with-page-dependencies/

Unless I'm misunderstanding what you need to achieve?

Edit: For EPiServer 7.5+ you should use CacheEvictionPolicy like:

EPiServer.CacheManager.Insert(
                key,
                item,
                new CacheEvictionPolicy(
                    new List<string>() { DataFactoryCache.PageCommonCacheKey(dependencyLink) }
                )
            );
Ted Nyberg
  • 7,001
  • 7
  • 41
  • 72
  • All of the methods that uses the CacheDependency-object is deprecated and tells you "Call the method Insert(string key, object value, CacheEvictionPolicy evictionPolicy) instead. Methods that take a CacheDependency instance cannot be used with anything but HttpRuntime.Cache. But will EPiServer's cache invalidation between servers work this way? – maets Mar 31 '15 at 06:51
  • I've added a CacheEvictionPolicy code sample to my original reply, hope that helps? Using CacheManager will allow cache invalidation across clustered servers. – Ted Nyberg Mar 31 '15 at 17:15
  • Yes. That helps. I looked with reflector and saw it really uses the ISynchronizedObjectInstanceCache instance from the ServiceLocator. But shouldn't use of the CacheManager-class be considered "not best practice"? In my opinion it feels like a very similar scenario to using the DataFactory-class instead of IContentRepository/IContentLoader. – maets Apr 01 '15 at 10:57
  • @maets Yep, just use `IObjectInstanceCache` instead of `CacheManager`, because the latter is just a static wrapper. – whyleee Apr 05 '15 at 09:50
0

I managed to solve this. Using the method found here.

I created a simple implementation like (not threadsafe):

    private static ISynchronizedObjectInstanceCache _cacheInstance;
    public static ISynchronizedObjectInstanceCache CacheImplementation
    {
        get
        {
            return (_cacheInstance ?? (_cacheInstance = ServiceLocator.Current.GetInstance<ISynchronizedObjectInstanceCache>()));
        }
        set
        {
            _cacheInstance = value;
        }
    } 
    public IList<MyObject> GetCachedObjects()
    {
        if (_cachedObjects == null)
        {
            object value = CacheImplementation.Get("MyObjectsCacheKey");
            if (value == null)
            {
                // Lookup objects (the slow function that triggered the need for caching)
                _cachedObjects = LookupMyObjects();
                string currentLanguage = ContentLanguage.PreferredCulture.Name;

                // Create dependencies and add to cache
                List<string> cacheDependencyKeys = new List<string>();

                // Add dependency to the start page
                cacheDependencyKeys.Add(DataFactoryCache.PageLanguageCacheKey(ContentReference.StartPage, currentLanguage));

                // Add dependency to the pointed out startpoint of the lookup of "MyObjects" (if not null)
                // This will force a cache invalidation when the page itself or it's children are changed.
                if (CurrentPage.MyObjectsStartPoint != null)
                {
                    cacheDependencyKeys.Add(DataFactoryCache.PageLanguageCacheKey(CurrentPage.MyObjectsStartPoint, currentLanguage));
                    cacheDependencyKeys.Add(DataFactoryCache.ChildrenCacheKey(CurrentPage.MyObjectsStartPoint));
                }
                // Do insert into cache
                CacheImplementation.Insert("MyObjectsCacheKey", _cachedObjects, new CacheEvictionPolicy(cacheDependencyKeys.ToArray()));
            } else 
            {
                _cachedObjects = value as IList<MyObject>;    
            }
        }
        return _cachedObjects;
    } private IList<MyObject> _cachedObjects = null;

Edit: Changed to ISynchronizedObjectInstanceCache instead of IObjectInstanceCache. EPiServer's "CacheManager"-class uses this implementation, and is supposed to work with cache invalidation between servers.

maets
  • 750
  • 6
  • 18