Caching in .NET Core

Mahesh Kantariya
Simform Engineering
6 min readJul 5, 2023

Maximize Speed and Responsiveness: Harnessing the Caching Magic in .NET Core.

In today’s digital landscape, where speed and responsiveness are extremely important, optimizing the performance of your applications is paramount. Caching plays a vital role in improving application performance and scalability.

In this blog post, we will look into the world of caching in .NET Core, investigating its various types, benefits, and when to use it in your web application.

What is Caching?

Caching is a process of storing frequently accessed data in a temporary storage location, known as a cache. The primary objective of caching is to accelerate data delivery to clients, as it eliminates the need to repeatedly fetch the same data from the original source.

Caching acts as a middle layer between the application and the data source, providing faster access and reducing the load on underlying systems.

But what happens if the data changes? Will it serve outdated information? There are multiple methods to refresh the cache and set the cache’s expiration date. Before we get into that, let’s quickly glance through the advantages of caching.

Benefits of using caching

Here are some key benefits of using caching:

  1. Enhanced performance: It improves performance by reducing the time and resources required to retrieve the data. By serving cached data, you can avoid expensive database queries, which results in faster response times.
  2. Scalability and concurrency: Caching can enhance the scalability of your application by reducing the load on backend systems. Your application can handle more concurrent requests and more users without experiencing performance issues by serving cached data.
  3. Offline support: Even when the backend systems or external services are temporarily unavailable, data can be served from the cache. By storing essential data in the cache, your application can continue to function and serve content to users during outages or connectivity issues.
  4. Lower latency: Caching the data enables faster access compared to retrieving data from disk or making network calls. This reduces latency and enhances the overall user experience by delivering data more quickly.

Types of caching techniques in .NET Core

Before moving ahead, we will create a .NET Core web app that will cover all the caching techniques.

So, let’s create it from the visual studio:

First, create a project with the ‘ASP.NET Core Web App (MVC)’ template.

Next, give a proper name for the web app and select your preferred framework version.

1. In-Memory caching: In this technique, the application stores temporary data in the main memory, which is RAM. The application holds some portions of the main memory as a cache to store the data. It is lightweight and suitable for scenarios where caching is required within a single instance of an application.

.NET Core has an `IMemoryCache` interface which provides an in-memory caching mechanism for storing and retrieving data.

Follow the steps below to implement in-memory caching in your web application.

Step 1: Add memory cache middleware in Program.cs

builder.Services.AddMemoryCache();

Step 2: Inject the IMemoryCache interface into the controller

public class ProductController : Controller
{
private readonly AppDbContext _dbContext;

private readonly IMemoryCache _memoryCache;


public ProductController(AppDbContext dbContext, IMemoryCache memoryCache)
{
_dbContext = dbContext;

_memoryCache = memoryCache;

}
}

Step 3: Implement a method that uses a memory cache.

public async Task<IActionResult> MemoryCache()
{
var cacheData = _memoryCache.Get<IEnumerable<Product>>("products");
if (cacheData != null)
{
return View(cacheData);
}

var expirationTime = DateTimeOffset.Now.AddMinutes(5.0);
cacheData = await _dbContext.Products.ToListAsync();
_memoryCache.Set("products", cacheData, expirationTime);
return View(cacheData);
}

2. Distributed caching: Distributed caching refers to the practice of sharing a common cache among multiple instances of an application. When a large cache is hosted on a single machine, it can become a performance bottleneck for the application. In contrast, distributing the cached data across multiple locations allows each cache to be more compact and lightweight.

Distributed caching has several advantages over other techniques. One notable benefit is that data remains intact even if a server is restarted. Additionally, distributed caching ensures data consistency across requests made to multiple servers.

In the context of .NET Core, there are various options available for implementing distributed caching. Some commonly used choices include:

  • SQL Server Cache
  • Redis Cache
  • NCache

To keep things brief, we’ll only discuss Redis cache in this article.

The IDistributedCache interface

Regardless of which approach you have implemented, the app interacts with the cache using this interface.

It provides a set of methods to manipulate items in distributed cache:

  1. Get or GetAsync: Accepts string key and retrieves value as byte[] array if found in the cache.
  2. Set or SetAsync: Adds an item (as byte[] array) to the cache using a string key.
  3. Refresh or RefreshAsync: Refreshes an item in the cache based on its key, resetting its sliding expiration timeout (if any).
  4. Remove or RemoveAsync: Removes a cache item based on its string key.

Follow the below steps to implement distributed cache using Redis.’

Step 1: To use Redis cache in your .NET Core application, you have to install the below package:

using Microsoft.Extensions.Caching.Redis;

Step 2: Add distributed Redis cache middleware using the ‘AddDistributedRedisCache’ method.

builder.Services.AddDistributedRedisCache(options => {
options.Configuration = "localhost:6379";
options.InstanceName = "";
});

For simplicity, we will use two options only: Configuration which specifies the path to Redis server, and InstanceName which specifies the name of Redis instance.

Step 3: Inject the IDistributedCache interface into the controller:

public class ProductController : Controller
{
private readonly AppDbContext _dbContext;

private readonly IDistributedCache _distributedCache;

public ProductController(AppDbContext dbContext, IDistributedCache distributedCache)
{
_dbContext = dbContext;
_distributedCache = distributedCache;
}
}

Step 4: Implement a method that uses distributed cache:

public async Task<IActionResult> DistributedCache()
{
var cacheData = await _distributedCache.GetStringAsync("products");
if (cacheData != null)
{
return View(JsonConvert.DeserializeObject<IEnumerable<Product>>(cacheData));
}

var expirationTime = TimeSpan.FromMinutes(5.0);
var products = await _dbContext.Products.ToListAsync();
cacheData = JsonConvert.SerializeObject(products);
var cacheOptions = new DistributedCacheEntryOptions().SetAbsoluteExpiration(expirationTime);
await _distributedCache.SetStringAsync("products", cacheData, cacheOptions);
return View(products);
}

3. Response caching: Response caching is specific to web applications and involves caching the entire HTTP responses generated by action methods.

.NET Core provides `[ResponseCache]` attribute and configuration options to enable this.

[ResponseCache(Location = ResponseCacheLocation.Any,Duration =10000)]
public async Task<IActionResult> ResponseCache()
{
var products = await _dbContext.Products.ToListAsync();
return View(products);
}

If you want to enable response caching at the global level, use the ‘AddResponseCaching’ method during application startup, which adds response caching middleware.

builder.Services.AddResponseCaching();

If you use this method, you don’t need to use the `[ResponseCache]` attribute for a specific method.

`[ResponseCache]` is helpful if you only need caching for specific actions and want more fine-grained control over caching options.

When to apply caching

Caching offers numerous benefits; it is very important to apply it strategically. Here are some common scenarios where caching can be beneficial:

  1. Expensive computation or I/O operations: If your application performs complicated tasks that take a lot of time and resources, as well as file operations that demand a lot of resources, like reading and parsing files, leverage caching to ensure optimum performance.
  2. Read-intensive applications: Caching is highly effective for read-intensive applications where multiple users access the same data.
  3. Frequent data retrieval: Apply caching when your application frequently accesses data from external sources, such as databases or APIs.
  4. Server-side rendering (SSR): When using server-side rendering frameworks like Razor or MVC, caching can be helpful in storing frequently accessed HTML pages.

Caching must be used judiciously, considering factors such as data volatility, cache expiration policies, cache invalidation mechanisms, and memory consumption.

Choosing the best technique

The question of which caching method is superior cannot be answered in a generalized way. The choice between the above three techniques depends on the specific requirement of your application.

Although there are some factors when choosing the best of them:

  • If an application needs to scale across multiple instances, the distributed cache is better to choose.
  • If the data stored in the cache is smaller, the in-memory cache can be helpful.
  • Response caching is more focused on caching the entire HTTP response generated by an action method in your .NET web application.

Wrapping up

Overall, Caching is an efficient way to optimize the performance and scalability of your application. By using it, you can reduce resource consumption and latency. Ultimately, it plays a role in improving the user experience of the systems. We just need to understand when and how to use it strategically to obtain the best results.

You can find the working code in this repo:

https://github.com/mahesh-k-simformsolutions/CachingTechniques

For more updates on the latest tools and technologies, follow the Simform Engineering blog.

Follow Us: Twitter | LinkedIn

--

--

Mahesh Kantariya
Simform Engineering

Experienced .NET Developer dedicated to crafting high-quality web applications. Lifelong learner. 🚀