Cache API changes


Describes breaking changes in the Cache API.

The Cache APIs were refactored for Sitecore 8.2. This refactoring includes a number of breaking changes that you must consider when you upgrade your solution to this new version.

Two interfaces, ICache<TKey> and ICache (implements interface ICache<string>), have been introduced. All Cache APIs use these abstractions instead of the Cache class. This enables you to implement adapters for external cache providers and to use these as the underlying containers in custom caches.

The top-level custom caches (for example, HtmlCache, XslCache, and so on) are unchanged except for the base class.. The custom caches are created mostly in DefaultCacheManager and in DatabaseCaches (single cache instance per database).

To use an external cache provider in a custom cache, implement either ICache or ICache<TKey>, depending on whether the custom cache uses string or object keys, and the external cache supports strings only or supports arbitrary objects as keys. After implementation, configure your custom cache to use the new ICache (or ICache<TKey>) implementation instead of the default in the CacheContainers.config file.

A number of overloads for the Add method that accepted a dataLength parameter have been removed:

  • void Add(object key, object data, long dataLength)

  • void Add(object key, object data, long dataLength, TimeSpan slidingExpiration)

  • void Add(object key, object data, long dataLength, DateTime absoluteExpiration)

  • void Add(object key, object data, long dataLength, TimeSpan slidingExpiration, DateTime absoluteExpiration)

  • void Add(ID key, object data, long dataLength)

  • void Add(string key, object data, long dataLength)

  • void Add(string key, object data, long dataLength, EventHandler<EntryRemovedEventArgs> removedHandler)

  • CacheEntry Add([NotNull] string key, [NotNull] object data, long dataLength, TimeSpan slidingExpiration)

  • CacheEntry Add([NotNull] string key, [NotNull] object data, long dataLength, DateTime absoluteExpiration)

Use ICacheSizeCalculationStrategy instead to calculate the size of the cache entries.

The ICacheSizeCalculationStrategy interface calculates the size of the cache entries and cache indexes (when applicable). It is called during each add to the cache to determine the size of the cache entry. The default DefaultCacheSizeCalculationStrategy is used for each cache. If the cache entry key and the cache entry data implement ICacheble, the GetDataLength method is used to get the size. If not, size calculation through reflection is used.

The CacheManager class is now a wrapper for the BaseCacheManager class. The implementation of BaseCacheManager is resolved using dependency injection and you can change it. The default implementation of BaseCacheManager is DefaultCacheManager, which contains most of the logic from CacheManager. BaseCacheManager also contains BaseCacheConfiguration that you use to define a custom cache container. You can configure it in CacheContainers.config.example. If no containers are specified for a cache, the default Sitecore.Caching.Generics.Cache<TKey> instance is used.

The GetNamedInstance method has been removed from the Cache class. You must use the method with the same name in the CacheManager class instead. This method requires a new Boolean parameter called registerNewInstance that decides whether to register the cache instance if you create a new cache instance inside CacheManager. If False, this cache will not be accessible through GetNamedInstance, FindCacheByName, or in GetAllCaches. When migrating, set registerNewInstance wto True because each instance of the cache was registered in previous versions.

GetAllCaches does not return full cache objects anymore. It returns an array of ICacheInfo, which contains basic properties about caches and does not contain operations for adding data. If you need to get full cache objects from ICacheInfo, use FindCacheByName with the name stored in ICacheInfo:

  • ICache FindCacheByName(string name), or

  • ICache<T> FindCacheByName<T>(string name)

Several caches use to contain indexes to improve performance when removing or retrieving cache records using partial keys. Caches with indexes have been refactored and indexes have been unified (except AcessResultCache and PathCache).

Cache containers that support indexing implement the IIndexedCache<T> interface. Because several caches (for example, ItemCache, and IsUserInRoleCache) had the same functionality, they have been unified. Each of them inherits CustomIndexedCache and has the GetIndexedCache method that enables you to specify custom implementation of IIndexedCache for the cache container. By default, IndexedCache<T> is used.

Indexes are hidden inside a cache and end users do not see them. They all inherit from the BaseCacheIndex base class. This class contains a default implementation for indexes. With each call of the indexedCache.Add or indexedCache.Remove, the appropriate method is called in the cache index. In order to define which keys should be used for indexing, ICacheIndex contains the GetIndexKeys method. For each index key returned, the index stores the current cache key. For example: IsUserInRole GetIndexKeys returns the account name and the role name, which means that for the cache key AccountName = “User”, RoleName = “Admin”, two index entries with the same cache key are created: one for the user and one for the role.

Follow these best practices when you work with the Cache API:

  • Avoid using the Cache class directly. Use the CacheManager class to retrieve an ICache object.

  • If you have complex keys or objects that you add to a cache, consider implementing the ICacheable interface for them. This enables you to define a size calculation inside the GetDataLength method and avoid expensive size calculation in strategy.

  • When you to add indexes for a cache, inherit from CustomIndexedCache<TKey>. Instantiate IIndexedCache in the GetIndexedCache method. You can use IndexedCache<T> by default. Then, implement ICacheIndex (inherit from BaseCacheIndex). It contains all the basic logic for working with indexes, but implement GetIndexKeys because this lets you define which keys are used to store data in the index.