Redis Caching in ASP.NET Core – Distributed Caching Detailed

by | Updated on Aug 8, 2020 | ASP.NET Core

In a Previous Article, we learnt 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 practial 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 Distribited 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. Distributed cache is a cache that can be shared by one or more applications / servers.
Like in-memory cache, it can improve your application response time quite drastrically. However, the implementation of Distributed Cache is application specific. This means that there are multiple cache providers that support distributed caches. 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 maintanence in the longer run.
  3. Cache would not be lost on server restart and application deployment as the cache lives external to the application.
  4. It does not use 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 AServer
  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 techgiants like Stackoverflow, Flickr, Github and so on.

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

In our context, Redis is a great option for implementing 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. Officialy, 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 memeory for multiple applications in the cloud. But let’s see how we can setup Redis on a Windows 10 Machine.

  • Download the ZIP Folder from this Github Repo. You could also use the MSI Executable.
redis download windows10
  • 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 server
  • Let’s check if the server is up and accessible. Minimze 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 a command “ping”. You will receive a status with “PONG” 😀
redis ping

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 port

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 cli port

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 redis cache and specify the port at which redis is available. To do this, navigate to starup.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 distributedCache 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 strimg to an object of type, List

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

DistributedCacheEntryOptions

  1. SetAbsoluteExpiration – Here you can set the expiration time of the cache object.
  2. SetSlidingExpiration – This is similar to the Absolute Expiration. It expires a cache 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.

before redis

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 directly to the redis cache, which should reduce the response time significantly. Let’s see.

after redis

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.

If you found this article helpful, consider supporting.

Buy me a coffeeBuy me a coffee

Summary

In this detailed article, we have learnt 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 learnt 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! 😀

2 Comments

  1. Raymon Mina

    may i ask what would be the response time for a second API call without redis cache ?

    Reply
    • Mukesh Murugan

      Hi,
      It depends on the complexity of your Db call. As it falls back to the DB Connection. In my example, it would go back to around 4-6 seconds. But you can keep the cache updated regularly by integrating Hangfire in the background.

      Regards

      Reply

Submit a Comment

Your email address will not be published. Required fields are marked *

Follow codewithmukesh

Support Me!

Buy me a coffeeBuy me a coffee

Pin It on Pinterest