.NET 8 Series has started! Join Now for FREE

8 min read

Redis Caching in ASP.NET Core - Distributed Caching Detailed

#dotnet

In a Previous Article, we learned about Caching, In-Memory Caching in ASP.NET Core, and other concepts related to caching. In this article, we will talk about Distributed Caching, Redis, Setting up Redis in Windows 10, Redis Caching in ASP.NET Core, and a small practical implementation too. Before Continuing, I recommend you to go through the previous article as well (In-Memory Caching in ASP.NET Core - Detailed Guide). The complete source code is available here.

What is Distributed Caching in ASP.NET Core?

ASP.NET Core supports not only in-memory application based cache but also supports Distributed Caching. A distributed cache is something external to the application. It does not live within the application and need not be present in the infrastructure of the server machine as well. A distributed cache is a cache that can be shared by one or more applications/servers.
Like an in-memory cache, it can improve your application response time quite drastically. However, the implementation of the Distributed Cache is application-specific. This means that there are multiple cache providers that support distributed caches. A few of the popular ones are Redis and NCache.

Pros & Cons of Distributed Caching

Pros.

  1. Data is consistent throughout multiple servers.
  2. Multiple Applications / Servers can use one instance of Redis Server to cache data. This reduces the cost of maintenance in the longer run.
  3. The cache would not be lost on server restart and application deployment as the cache lives external to the application.
  4. It does not use the local server’s resources.

Cons.

  1. Since it is kept external, the response time may be a bit slower depending on the connection strength to the Redis server.

IDistributedCache interface

This is the interface you need, to access the distributed cache objects. IDistributedCache Interface provides you with the following methods to perform actions on the actual cache.

  1. GetAsync - Gets the Value from the Cache Server based on the passed key.
  2. SetAsync - Accepts a key and Value and sets it to the Cache server
  3. RefreshAsync - Resets the Sliding Expiration Timer (more about this later in the article) if any.
  4. RemoveAsync - Deletes the cache data based on the key.

What is Redis?

Redis is an open-source data store that is used as a database, cache / messaging broker. It supports quite a lot of data structures like string, hashes, lists, queries, and much more. It’s a blazing fast key-value based database that is written in C. It’s a NoSQL Database as well, which is awesome. For these purposes, it is being used at tech giants like Stackoverflow, Flickr, Github, and so on.

Ultimately it helps you save a lot of dollars in the longer run.

In our context, Redis is a great option for implementing a highly available cache to reduce the data access latency and improve the application response time. As a result, we can reduce the load off our database to a very good extent.

Setting up Redis on Windows 10

As mentioned earlier, Redis is built to run on Linux, OSX, and BSD Operating Systems. Officially, it has no support for Windows-based Operating System. But there are a bunch of ports available for Windows 10. Ideally, developers use a secondary machine that takes care of caching, where Redis runs and can serve as a cache memory for multiple applications in the cloud. But let’s see how we can set up Redis on a Windows 10 Machine.

  • Download the ZIP Folder from this Github Repo. You could also use the MSI Executable.

redis-caching-in-aspnet-core

  • Extract the Zip Folder and Open up redis-server.exe. That’s it, The Redis Server is now running on your machine. DO NOT CLOSE this Window.

redis-caching-in-aspnet-core

  • Let’s check if the server is up and accessible. Minimize the Redis-server.exe and open up Redis-cli.exe. This is a window with which you can actually access Redis. To test if the server is alive, just enter the command “ping”. You will receive status with “PONG” :D

redis-caching-in-aspnet-core

Note that I have also written certain commands to get/set cache entry within Redis. You might have seen something similar in the previous article where we used In-Memory Caching in ASP.NET Core.

Getting to know Redis Better

By default, Redis runs on the local 6379 port. To change this, open up Powershell and run the following command.

./redis-server --port {your_port}

redis-caching-in-aspnet-core

Once Redis is running at your defined port, the Redis CLI would no longer work. This is because it tries to connect to 6379 by default. To override this, open up PowerShell again and enter the following command.

./redis-cli -p {your_port}

redis-caching-in-aspnet-core

Redis CLI Commands

Here are some important CLI commands of Redis that you would want to know.

Setting a Cache Entry

-> Set name "Mukesh"
OK

Getting the cache entry by key

-> Get name
"Mukesh"

Deleting a Cache Entry

-> Get name
"Mukesh"
-> Del name
(integer)1
-> Get name
(nil)

Setting a key with expiration time (in seconds)

-> SETEX name 10 "Mukesh"
Ok

Get the Time left to expire(in seconds)

->TTL name
(integer)5

Integrating Redis Caching in ASP.NET Core

Let’s get started with implementing Redis Cache in ASP.NET Core. For this demonstration, I will be using the API that we had built in the previous article (In-Memory Caching). This API is connected to DB via Entity Framework Core. It has a single purpose, return a list of customers (over 1000 records).

We will build a new endpoint that implements Redis Distributed Caching.

First, let’s install a package that helps you communicate with the Redis server.

Install-Package Microsoft.Extensions.Caching.StackExchangeRedis

MAKE Sure that your Redis Server is up and running in the background.

After that, we have to configure our application to support the Redis cache and specify the port at which Redis is available. To do this, navigate to startup.cs/ConfigureServices method and add the following.

services.AddStackExchangeRedisCache(options =>
{
options.Configuration = "localhost:4455";
});

IMPORTANT - Make sure to change the port number to the actual Redis port.

As mentioned earlier, we need to use the IDistributedCache to access the configured Cache which in our case is the Redis server. Let’s inject this interface into the CustomerController’s Constructor.

private readonly IMemoryCache memoryCache;
private readonly ApplicationDbContext context;
private readonly IDistributedCache distributedCache;
public CustomerController(IMemoryCache memoryCache, ApplicationDbContext context, IDistributedCache distributedCache)
{
this.memoryCache = memoryCache;
this.context = context;
this.distributedCache = distributedCache;
}

With that out of the way, let’ create a new endpoint in our CustomerController and name it GetAllCustomersUsingRedisCache. This is going to be a GET method with the route set to api/customer/redis

[HttpGet("redis")]
public async Task<IActionResult> GetAllCustomersUsingRedisCache()
{
var cacheKey = "customerList";
string serializedCustomerList;
var customerList = new List<Customer>();
var redisCustomerList = await distributedCache.GetAsync(cacheKey);
if (redisCustomerList != null)
{
serializedCustomerList = Encoding.UTF8.GetString(redisCustomerList);
customerList = JsonConvert.DeserializeObject<List<Customer>>(serializedCustomerList);
}
else
{
customerList = await context.Customers.ToListAsync();
serializedCustomerList = JsonConvert.SerializeObject(customerList);
redisCustomerList = Encoding.UTF8.GetBytes(serializedCustomerList);
var options = new DistributedCacheEntryOptions()
.SetAbsoluteExpiration(DateTime.Now.AddMinutes(10))
.SetSlidingExpiration(TimeSpan.FromMinutes(2));
await distributedCache.SetAsync(cacheKey, redisCustomerList, options);
}
return Ok(customerList);
}

Line 4 - We set the key internally in the code.
Line 6 - Initialize an empty List of Customers.
Line 7 - access the distributed cache object to get data from Redis using the key “customerList”
Line 8 - If the key has a value in Redis, then convert it to a list of Customers and send back the data.
Line 13 - If the value does not exist in Redis, then access the database via efcore, get the data and set it to redis.

Line 10 - The data will be stored in Redis as a byte array. We will be converting this array of a string.
Line 11 - Converts the string to an object of type, List

Line 16 - Converts a list of customers to a string using NewtonSoft.
Line 17- Converts the string to a Byte Array. This array will be stored in Redis.

DistributedCacheEntryOptions -

  1. SetAbsoluteExpiration - Here you can set the expiration time of the cached object.
  2. SetSlidingExpiration - This is similar to Absolute Expiration. It expires as a cached object if it not being requested for a defined amount of time period. Note that Sliding Expiration should always be set lower than the absolute expiration.

Line 21 - Finally, set the cache.

Let’s test our implementation via Postman now.

This is the expected result. First call will take a longer time. Second call should take a fraction of that response time.

Open up postman and send a GET request to ./api/customer/redis. We are trying to pull 1000s of records.

redis-caching-in-aspnet-core

As you can see, the first API call took about 8 seconds to return a response. Now, if everything worked, during the first call the cache for customerList also would be set by our API onto the Redis server. Thus, the second call would be direct to the Redis cache, which should reduce the response time significantly. Let’s see.

redis-caching-in-aspnet-core

There you go, just 56ms. That’s quite a lot of response time saved, yeah?

By now, you can understand the need to implement caching in all your ASP.NET Core Applications.

Summary

In this detailed article, we have learned about Distributed Caching, Redis, How to setup Redis in Windows 10, IDistributedCache interface, and finally a small sample to Integrate Redis Caching in ASP.NET Core. You can find the completed source code here. I hope you learned something new and detailed in this article. If you have any comments or suggestions, please leave them behind in the comments section below. Do not forget to share this article within your developer community. Thanks and Happy Coding!

Source Code ✌️
Grab the source code of the entire implementation by clicking here. Do Follow me on GitHub .
Support ❤️
If you have enjoyed my content and code, do support me by buying a couple of coffees. This will enable me to dedicate more time to research and create new content. Cheers!
Share this Article
Share this article with your network to help others!
What's your Feedback?
Do let me know your thoughts around this article.

Boost your .NET Skills

I am starting a .NET 8 Zero to Hero Series soon! Join the waitlist.

Join Now

No spam ever, we are care about the protection of your data. Read our Privacy Policy