When coding a Sitecore solution you sometimes need a cache to store some values.
I’ve seen a lot of different cache implementations in Sitecore solutions that do not use the Sitecore API. Such an implementation could for example use a static or perhaps a singleton some even go further and use a custom database or a nosql document database such as RavenDB or Mongo.
It is very rare that these implementations could not simply be replaced by using the built-in Sitecore caching API.
To implement a simple cache you simply derive from the Sitecore class called CustomCache.
1 2 3 4 5 6 7 |
public class DesignBundleCache : CustomCache { public DesignBundleCache(long maxSize) : base("DesignResources.DesignBundleCache", maxSize) { } } |
You need to create a class constructor that calls the base constructor with the name of the cache and the max allowed size.
Then you can either wrap access to your cache in a static like below
1 2 |
public static readonly DesignBundleCache DesignBundleCache = new DesignBundleCache(StringUtil.ParseSizeString(Settings.GetSetting("DesignResources.DesignBundleCacheMaxSize", "50MB"))); |
Notice the call to Sitecore.StringUtil.ParseSizeString( .. ), this method converts a string such as 512KB or 10MB to a long representing the size in bytes. This makes configuration of sizes easy to read.
Or you can simply instantiate the cache each time you need it. This will make Sitecore look for a cache with that name and then take the existing cache instance if any and wrap it as the inner cache of your custom cache. Calling the constructor each time you need to cache can be fine if your cache constructor do not have parameters, otherwise the static approach is better.
The most basic usage of a custom cache is to use it for storing string values. Then you just call GetString and SetString on the CustomCache base class from Get and Set methods within your derived class.
1 2 3 4 5 6 7 8 9 |
public string Get(string cacheKey) { return GetString(cacheKey); } public void Set(string cacheKey, string value) { SetString(cacheKey, value); } |
If you need to cache complex objects you can do this as well. Then you have to write a class that implements the ICacheable interface.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public class DesignResourceFile : ICacheable { public byte[] Content { get; set; } public DateTime LastModified { get; set; } public string ETag { get; set; } public string MimeType { get; set; } public long GetDataLength() { return Content.Length; } public bool Cacheable { get; set; } public bool Immutable { get { return true; } } public event DataLengthChangedDelegate DataLengthChanged; } |
Then you call the Get and Set methods of the CustomCache base class from within your derived class.
1 2 3 4 5 6 7 8 9 |
public DesignResourceFile Get(string cacheKey) { return (DesignResourceFile) GetObject(cacheKey); } public void Set(string cacheKey, DesignResourceFile designResourceFile) { SetObject(cacheKey, designResourceFile); } |
A CustomCache will be maintained by Sitecore when it is instantiated. This is done by the CustomCache base constructor that registers the instantiated cache class. As mentioned previously only one cache can exists with the same name. If another class is instantiated with the same name but different max size then it will still be the original cache instance that is used and the max size will not be changed.
Now when Sitecore is maintaining your cache you are also able to see how it is being utilized on the admin page /sitecore/admin/cache.aspx
The cache is cleared when CacheManager.ClearAllCaches(); is called and can also be cleared by itself by calling Clear();
It is really super easy to create your own custom caches in Sitecore. Of course beware of the memory consumption and do please configure your cache sizes to match with the environments that the solution runs in.
Sitecore caching does not distribute across different Sitecore instances. Not yet at least, they are right now in memory per instance. If this changes one day in the future then I am sure that Sitecore will do their best to keep the development interface to the caches similar so if they choose to change their underlying technologý that our custom caches still will work with little or no modification.
This is the last post I will write today, see the two previous ones as well, the first about matching hostname wildcards in Sitecore and the other about sending mails using the Sitecore API.
Anders Laub Christoffersen
Anders has been working with Sitecore for over a decade and has in this time been the lead developer and architect on several large scale enterprise solutions all around the world. Anders was appointed the title of Sitecore Technical MVP in 2014 and has been re-appointed the title every year since then.
- Web |
- More Posts
Hi Anders
Some great posts on Sitecore. I don’t really see the point in always using Sitecores abstractions or implementations though. In this case why not replace all that code and configuration with use of a . NET MemoryCache? And in one of your previous posts use a SmtpClient directly instead of Sitecores abstraction in some utility class? I haven’t looked at their implementation, but SmtpClient is soo easy to use, and has non-blocking async methods. Why not utilize the full power of that class?
Hi Andreas,
Thanks for the comments.
Regarding utilizing the Sitecore caches rather than using a MemoryCache or other standard .NET implementation is to rely on Sitecore to maintain the cache layers instead of taking that responsibility in your own code. There can of course be a few cases where you prefer to keep the full control over the cache and write your own but these cases are rare. There can also be rare cases where you might need a distributed cache on Redis or similar.
Regarding the SendMail method then using this will only save you a few lines of code compared to instantiating a SmtpClient. The SendMail method is not async so it does not cover all needs. The main point of using this method instead of writing it yourself is also to re-use the settings that Sitecore ships with so you don’t have several Smtp server settings in configuration or elsewhere that you need to maintain.
If you need to send a mail async you can simply configure a SmtpClient instance using Sitecore.Configuration.Settings.MailServer etc. and then call SendAsync( .. )
–Anders