How-To: MemoryCache in CSharp

Introduction to MemoryCache in C#

Cache

MemoryCache is a fundamental component for caching management in C#. It resides in the System.Runtime.Caching library and is used to temporarily store data in memory to improve application performance, reducing the time it takes to access data compared to retrieval from a slower data source such as a database or network call.

What is MemoryCache?

MemoryCache provides an in-memory caching implementation that allows developers to store data in the application process memory.
This is particularly useful for applications needing quick access to frequently used data.
The cache can be configured to store data for a certain period of time or until a certain maximum capacity is reached.

Using MemoryCache

Below is a simple example of how to use MemoryCache to store and retrieve data in memory:

using System;
using System.Runtime.Caching;

class Program
{
 static void Main(string[] args)
 {
     // Creating a MemoryCache object
     MemoryCache cache = MemoryCache.Default;

     // Adding an item to the cache with a key and value
     cache.Add("myKey", "Hello, World!", DateTimeOffset.UtcNow.AddMinutes(10));

     // Retrieving the item from the cache
     string cachedValue = cache.Get("myKey") as string;
     Console.WriteLine(cachedValue); // Output: Hello, World!
 }
}

In this example, we’ve created a default MemoryCache object and added a value to the cache with a key “myKey” that will expire after 10 minutes.

Advanced Cache Management

In addition to adding and retrieving items from the cache, MemoryCache offers advanced features for cache management such as defining custom expiration policies for cache items.

Below is a more complex example where we prevent a cache entry from expiring if it meets certain requirements:

using System.Collections.Generic;
using System.Linq;
using System.Runtime.Caching;

namespace Sandbox.ServerCacheManager
{
 /// <inheritdoc cref="ICacheManager"/>
 public sealed class CacheManager : ICacheManager
 {
     // CacheManager as Singleton
     private static CacheManager _instance;
     private readonly MemoryCache _memoryCache;
     private const int ExpirationTimeInMinutes = 60;

     #region Ctor

     /// <summary>
     /// Ctor of <see cref="CacheManager"/>.
     /// </summary>
     private CacheManager()
         : this(new MemoryCache("CacheManagerTest"))
     { }

     /// <summary>
     /// Ctor of <see cref="CacheManager"/>.
     /// </summary>
     /// <param name="memoryCache">An instance of <see cref="MemoryCache"/>.</param>
     internal CacheManager(MemoryCache memoryCache)
     {
         _memoryCache = memoryCache;
     }

     /// <inheritdoc cref="ICacheManager.GetInstance()" />
     public static CacheManager GetInstance()
     {
         if (_instance != null)
             return _instance;

         _instance = new();

         return _instance;
     }

     #endregion


     /// <inheritdoc cref="CacheManager.SetCache(string, List{string})" />
     public void SetCache(string key, string objectToCache)
     {
         _memoryCache.Set(key, objectToCache, CreateCacheItemPolicy());
     }

     /// <inheritdoc cref="CacheManager.GetCache(string)" />
     public string GetCache(string key)
     {
         return _memoryCache.Get(key) as string;
     }

     private void CheckExpirationAndValidity(CacheEntryUpdateArguments arguments)
     {
         var refreshedData = GetCache(arguments.Key);

         if (refreshedData.StartsWith("Hello"))
         {
             arguments.UpdatedCacheItem = new CacheItem(arguments.Key, refreshedData);
             arguments.UpdatedCacheItemPolicy = CreateCacheItemPolicy();
         }
     }

     private CacheItemPolicy CreateCacheItemPolicy()
     {
         return new CacheItemPolicy()
         {
             AbsoluteExpiration = DateTimeOffset.UtcNow.AddMinutes(ExpirationTimeInMinutes),
             UpdateCallback = CheckExpirationAndValidity
         };
     }
 }
}

In this example, we added an item to the cache with a 10-minute expiration policy. Then, we checked if the cached item starts with “Hello”, and if so, we extended the cache duration to one hour.

Class Explanation

This C# code defines a class called CacheManager within the namespace Sandbox.ServerCacheManager.
Here’s a detailed explanation of its main parts:

  1. MemoryCache: The CacheManager class utilizes an instance of the MemoryCache class (from the System.Runtime.Caching library) to store cached data in memory.

  2. Singleton Pattern: The CacheManager class is implemented as a Singleton, meaning that only one instance of it can exist in the application. This is achieved by maintaining a private static _instance field and a GetInstance() method that returns the existing instance if it has already been created, or creates a new one if it doesn’t exist yet.

  3. Constructors: The class has two private constructors. The first private constructor is used to create an instance of CacheManager with a new instance of MemoryCache named “CacheManagerTest”. The second constructor accepts an instance of MemoryCache and is used internally for initialization.

  4. SetCache and GetCache Methods: These methods allow setting and retrieving data in the cache. The SetCache method adds an object to the cache with a specified key, while the GetCache method retrieves the object from the cache associated with the specified key.

  5. CheckExpirationAndValidity Method: This method is called when an object in the cache needs to be updated (also when the object needs to be removed). It checks if the data in the cache meets certain criteria (e.g., if it starts with “Hello”), and if so, it updates the cache item and its expiration policy. In this example, the chache will never expire.

  6. CreateCacheItemPolicy Method: This method creates a new instance of CacheItemPolicy, which contains information about the expiration policy of the cache item. In this case, an hour is set as the absolute expiration time for cache items, and a callback function (UpdateCallback) is specified that will be called when a cache item is updated.

Conclusion

MemoryCache is a powerful tool for improving C# application performance by temporarily storing data in memory. You can configure the cache according to the specific needs of the application and utilize advanced features such as defining custom expiration policies to manage the cache more effectively.