In-Memory Caching In ASP.NET Core

Introduction

In general terms, caching takes place where frequently-used data is stored so that the application can quickly access the data rather than accessing the data from the source. Caching can improve the performance and scalability of the application dramatically and can help us to remove the unnecessary requests to the external data sources for the data that changes infrequently.

ASP.NET Core has a rich support for caching and it supports different kinds of caching. In this article, we will talk about "In-Memory" cache. This is the simplest way of caching. In this technique, cache is stored in the memory of the local Web Server.

An in-memory cache is stored into the Server memory which is hosting the ASP.NET application. In the case of Web farm (where the application is hosted on multiple servers) or cloud hosting environments, all servers may have different values of in-memory cache. So, in-memory caching cannot be used in web farm or cloud hosting environments. For this type of environment, distributed cache is best suited.

How to configure In-Memory Caching in ASP.NET Core

To use in-memory cache in our ASP.NET Core project, first we need to add "Microsoft.Extensions.Caching.Memory" in project.json file.

Project.json

  1. {  
  2.   "version""1.0.0-*",  
  3.   "buildOptions": {  
  4.     "preserveCompilationContext"true,  
  5.     "debugType""portable",  
  6.     "emitEntryPoint"true  
  7.   },  
  8.   "dependencies": {},  
  9.   "frameworks": {  
  10.     "netcoreapp1.0": {  
  11.       "dependencies": {  
  12.         "Microsoft.NETCore.App": {  
  13.           "type""platform",  
  14.           "version""1.0.1"  
  15.         },  
  16.     "Microsoft.AspNetCore.Server.Kestrel""1.0.0",  
  17.     "Microsoft.AspNetCore.Mvc""1.0.0",  
  18.     "Microsoft.Extensions.Caching.Memory""1.0.0"  
  19.       },  
  20.       "imports""dnxcore50"  
  21.     }  
  22.   }  
  23. }  
Caching is a Service in ASP.NET Core, so we need to add the caching Service to the "ConfigureServices" method of Startup class.

Startup.cs
  1. public class Startup{  
  2.     public void ConfigureServices(IServiceCollection services)  
  3.     {  
  4.         services.AddMvc();  
  5.         services.AddMemoryCache();  
  6.     }  
  7. ….  
  8. ….  
  9. }  
ASP.NET Core MVC Controller is able to request their dependencies explicitly via their constructors. We utilize the caching in our application by requesting an instance of IMemoryCache in our Controller (or middleware) constructor. In the following code snippet, I am using the controller component to handle the instance of IMemoryCache.
  1. public class HomeController : Controller  
  2. {  
  3.     IMemoryCache _memoryCache;  
  4.     public HomeController(IMemoryCache memoryCache)  
  5.     {  
  6.         _memoryCache = memoryCache;  
  7.     }  
  8. ….  
  9. ….  
  10. …  
  11. }  
Reading and Writing In-Memory cache

There are two methods available for reading from In-Memory cache.
  • "Get this" will return the value if it exists otherwise returns "null".
  • "TryGetValue" will assign the cache value to the out parameter and returns true when value exists in cache; else it returns false.

There is "Set" method available for writing the data into the cache. This method accepts a key which is used for looking up values that are data cached by the user, and a set of MemoryCacheEntryOptions.

The "MemoryCacheEntryOption" allows us to specify

  • Absolute or sliding time-based cache expiration
  • Caching priority
  • Callbacks
  • Dependencies

In the following example, I have created two Controller Action methods - one for setting the cache and the other for retrieving the cache.

HomeController.cs

  1. public class HomeController : Controller  
  2. {  
  3. ….  
  4. ….  
  5. …..  
  6.     [Route("home/SetCacheData")]  
  7.     public IActionResult SetCacheData()  
  8.     {  
  9.         var Time =  DateTime.Now.ToLocalTime().ToString() ;  
  10.         MemoryCacheEntryOptions cacheOption = new MemoryCacheEntryOptions()  
  11.             {  
  12.               
  13.                 AbsoluteExpirationRelativeToNow = (DateTime.Now.AddMinutes(1) - DateTime.Now  )  
  14.             };  
  15.   
  16.   
  17.         _memoryCache.Set("Time", Time, cacheOption);  
  18.         return View();  
  19.     }     
  20.     [Route("home/GetCacheData")]  
  21.     public IActionResult GetCacheData()  
  22.     {  
  23.         string Time = string.Empty;  
  24.         if(!_memoryCache.TryGetValue("Time", out Time))  
  25.         {  
  26.             Time = "Cache is expired or not available";  
  27.         }  
  28.         ViewBag.data = Time;  
  29.         return View();  
  30.     }  
  31. ….  
  32. ….  
  33. ….  
  34. }  
In the method “SetCacheData”, I have defined AbsoluteExpirationRelativeToNow to one minute, so the cache will expire after one minute.

Output



We can set the following properties of "MemoryCacheEntryOptions" class to get the desired behavior of cache.
  • AbsoluteExpiration - It gets or sets the absolute expiration date for the cache entry.
  • AbsoluteExpirationRelativeToNow - It gets or sets an absolute expiration time, relative to current date and time.
  • ExpirationTokens - It uses token instance to expire the cache entry.
  • PostEvictionCallbacks -  It gets or sets a callback that will be fired after the cache entry is removed from the cache.
  • Priority -  It gets or sets the priority for keeping the cache alive in memory during cache cleanup triggering.
  • SlidingExpiration - It gets or sets the value in timespan for how long a cache entry can be inactive before removing it from the cache.

Remove data from the cache

Using "Remove" method of IMemoryCache interface, we can remove the cache from the memory.

  1. _memoryCache.Remove("Time");  
Cache Callbacks

We can configure cache dependency. It may be dependent on other cache entries, programmatic tokens and the file system etc. We can also register the callback when cache is removed from the memory.
  1. MemoryCacheEntryOptions cacheOption = new MemoryCacheEntryOptions()  
  2.            {  
  3.                AbsoluteExpirationRelativeToNow = (DateTime.Now.AddMinutes(1) - DateTime.Now),  
  4.            };  
  5.        cacheOption.RegisterPostEvictionCallback(  
  6.            (key, value, reason, substate) =>  
  7.            {  
  8.               Console.Write("Cache expired!");  
  9.            });  
This callback is run on the different threads from the thread on which the cache removal code is run. This callback method also provides us a reason for moving the cache value. The possible values are None, Removed, Replaced, Expired, TokenExpired and Capacity.

Summary

In-Memory cache allows us to store the data into the server memory and helps us to improve the performance of the application by removing unnecessary requests to external data sources. It is very simple to use. This approach of caching will not be used when the app is hosted on multiple servers in a web farm or cloud hosting environment.

I would recommend the following articles which provide more information about ASP.NET Core.
  1. Introduction To ASP.NET Core
  2. Build Your First ASP.NET MVC Core Application With Visual Studio Code
  3. Performing CRUD Operations With ASP.NET MVC Core And Entity Framework Core