ASP.NET Core In-Memory Caching
Caching can be used to improve the performance of an application. For an example, say that you have an API endpoint and there, you are returning some data after querying a database, and you are sure the related data is not going to get refreshed for a certain period of time, maybe daily. In that case, there is no point of querying the database each time your endpoint is being called within that day. So in the initial call, you can query the database, cache them and for the next subsequent calls, you can return the data from the cache. Then after that certain period of time expires, elicit the data in the cache and start from the beginning.
The in-memory caching uses web servers memory to store the cache. So now an interesting question comes, what if the application is running on multiple servers then how can the cache is shared. In such scenario, either we will need to enforce sticky sessions (specific session and all its subsequent sessions being directed to the same server) or distributed caching (doesn't use local memory and uses some other providers to maintain the cache Microsoft SQL Server, Redis etc.). In this post, we are assuming sticky sessions are in place.
ASP.NET Core provides 2 options.
public class MemoryCache : IDisposable, Microsoft.Extensions.Caching.Memory.IMemoryCache
This one is the preferred in the world of ASP.NET Core, as you can see it implements IMemoryCache and nicely integrated to ASP.NET Core DI.
public class MemoryCache : System.Runtime.Caching.ObjectCache, IDisposable
This one comes for .NET Framework, but still as long you target .NET Standard 2.0 or above, you can use this.
Now let’s see how we can use in-memory caching using Microsoft.Extensions.Caching.Memory.MemoryCache.
Let's assume we have created an ASP.NET Core Web API application using the default template.
First, you need to register IMemoryCache. We don’t explicitly need to register, there is an extension method already available.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddMemoryCache();
}
Next, in the controllers’ constructor, we can inject IMemoryCache.
public IMemoryCache _memoryCache { get; }
public ValuesController(IMemoryCache memoryCache)
{
_memoryCache = memoryCache;
}
And use as follows.
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
string key = "Somekey";
if (!_memoryCache.TryGetValue(key, out DateTime cacheValue))
{
cacheValue = DateTime.Now;
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromSeconds(30));
_memoryCache.Set(key, cacheValue, cacheEntryOptions);
}
return new string[] { $"Cached: { cacheValue.ToString()}", $"Actual: { DateTime.Now.ToString()}" };
}
The cache contains EntriesCollection which is maintained using keys. The logic is simple, we are adding items to EntriesCollection identified by a key, and when we add we can set a variety of options (MemoryCacheEntryOptions).
- AbsoluteExpiration
Gets or sets an absolute expiration date for the cache entry.
- AbsoluteExpirationRelativeToNow
Gets or sets an absolute expiration time, relative to now.
- ExpirationTokens
Gets the IChangeToken instances which cause the cache entry to expire.
- PostEvictionCallbacks
Gets or sets the callbacks will be fired after the cache entry is evicted from the cache.
- Priority
Gets or sets the priority for keeping the cache entry in the cache during a memory pressure triggered cleanup. The default is Normal.
- Size
Gets or sets the size of the cache entry value.
- SlidingExpiration
Gets or sets how long a cache entry can be inactive (e.g. not accessed) before it will be removed. This will not extend the entry lifetime beyond the absolute expiration (if set).
More reading
Cache in-memory in ASP.NET Core