Caching is a technique in which frequently used data is added to some memory that makes a request to this data faster as there is no need to fetch this data from the database for each request. ASP.NET Core caching provides support for several different types of Caches like in-memory cache, distributed cache, and response caching.
The cache is short term memory which has limited space but is fast. Normally data required for an application is stored in some database and in caching frequently used data from this database is added to some cache memory. The in-memory and distributed cache store data in memory as key-value pairs.
Caching can increase the complexity of the application so we must be always cautious while deciding upon the need for caching in the application. Also, the application should never depend only on cache data i.e. in case of failure of cache application should be smart to fetch data from the database. A cache hit occurs when requested data is fetched from cache and its cache miss when requested data is not present in the cache.
The cache can be maintained on each server or also a centralized cache can be maintained that is accessed by all the servers. In-memory cache is maintained on the server where the application is hosted. This in-memory works fine when we have a single server but in Web Farm scenario it is preferable to implement a distributed cache.
Benefits of Caching
- Improves performance by reducing response time as Cache memory is faster than main memory
- Lowers utilization of resources like CPU, network & database.
- ASP.NET Core Caching improves the overall experience for users.
Implement In-memory cache
Im-memory is the simplest cache implementation. In-memory caching is implemented as a service which is called by dependency injection. In-memory cache which uses IMemoryCache interface requires the implementation of Nuget Package ‘Microsoft.Extensions.Caching.Memory’
To implement ASP.NET Core caching we need to register In-memory cache service in the ConfigureServices method of Startup class as shown below.
public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); //To use in memory cache services.AddMemoryCache(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); } }
We need to inject IMemoryCache interface in the constructor of the controller. As shown below it has been injected in BooksController.
public class BooksController : ControllerBase { private readonly ILogger<BooksController> _logger; private readonly IMemoryCache _memoryCache; public BooksController(ILogger<BooksController> logger, IMemoryCache memoryCache) { _logger = logger; _memoryCache = memoryCache; } public async Task<List<string>> GetBookList(string authorName) { try { var authorKey = authorName.ToLower(); if(!_memoryCache.TryGetValue(authorKey,out List<string> bookList)) { bookList = await BookAPIService.GetBookList(authorName); var cacheEntryOptions = new MemoryCacheEntryOptions { AbsoluteExpiration = DateTime.Now.AddMinutes(30) }; _memoryCache.Set(authorKey, bookList, cacheEntryOptions); } return bookList; } catch(Exception ex) { _logger.LogError(ex, ex.Message); throw ex; } } }
In the above code, we first check if the book list exists in our local in-memory cache and return from there if it does. Otherwise, we call the external API to get the list of books matching with provided author name and then we cache the result.
Cache expiration option is also set to 30 minutes i.e. after 30 minutes this cache entry will become invalid.
Following methods are used in above code:
- TryGetValue – tries to read from the cache and if entry is available then set its value to out parameter. Return true if the specified key exists otherwise it returns false.
- Set – writes data in cache against the specified key. Also, it takes cache options which sets expiration for data to 30 minutes.
Conclusion
ASP.NET Core caching can be used to improve application performance and scalability. The in-memory cache can be used to improve the performance of the web application. In-memory cache is preferable only when we have a single server.
You can also check my another Article explaining ASP.NET Core Middleware – https://procodeguide.com/programming/aspnet-core-middleware/
References: https://docs.microsoft.com/en-us/aspnet/core/performance/caching/memory?view=aspnetcore-3.1