Implementation Of The Redis Cache In The .NET Core API

Tohid haghighi
6 min readAug 10, 2023

--

We are going to discuss Caching in .NET Core and how it works. So, we look at the following things one by one.

  • Introduction of Caching
  • What is Cache
  • Types of cache
  • Cache Implementation

So, let’s start one by one.

Redis + DotNetcore

Introduction

Caching is very popular nowadays in the software industry because it will improve the performance and scalability of the application. We use many web applications like Gmail and Facebook and see how responsive they are and we have a great user experience. There are a lot of users using the internet and if an application has huge network traffic and demand, we need to take care of many things which help us to improve the performance and responsiveness of the application. So, because of that, there is the solution of caching and that’s why caching comes into the picture.

What is Caching?

The cache is the memory storage that is used to store the frequent access data into the temporary storage, it will improve the performance drastically and avoid the unnecessary database hit and store frequently used data into the buffer whenever we need it.

As you see in the above image there are two scenarios, one is without using cache and another is with cache. So here when we do not use the cache, in that case, suppose users want data then they will hit each time database and it will increase the time complexity and reduce performance in case there is some static data users want and it is the same for all users. In that case when we do not use cache then each one hits the unnecessary database to fetch data. On the other side as you can see we use cache, and in that case if there is the same static and the same data for all users then only the first user will hit the database and fetch data and store it into the cache memory and then other two users used that from the cache without unnecessarily hit database to fetch data.

Types of Cache

Basically, there are two types of caching .NET Core supports

  1. In-Memory Caching
  2. Distributed Caching

When we use In-Memory Cache then in that case data is stored in the application server memory and whenever we need then we fetch data from that and use it wherever we need it. And in Distributed Caching there are many third-party mechanisms like Redis and many others. But in this section, we look into the Redis Cache in detail and how it works in the .NET Core

Distributed Caching

Distributed Cache
  • Basically, in the distributed caching data are stored and shared between multiple servers
  • Also, it’s easy to improve scalability and performance of the application after managing the load between multiple servers when we use multi-tenant application
  • Suppose, In the future, if one server is crashed and restarted then the application does not have any impact because multiple servers are as per our need if we want

Redis is the most popular cache which is used by many companies nowadays to improve the performance and scalability of the application. So, we are going to discuss Redis and usage one by one.

Redis Cache

  • Redis is an Open Source (BSD Licensed) in-memory Data Structure store used as a database.
  • Basically, it is used to store the frequently used and some static data inside the cache and use and reserve that as per user requirement.
  • There are many data structures present in the Redis which we are able to use like List, Set, Hashing, Stream, and many more to store the data.

Installation of Redis Cache

Install Redis in docker

docker pull redis

Create container with

docker run -p 9191:6379 -d --name RedisCache redis --requirepass '123456'

Start Docker container

docker start RedisCache

Execute Redis in powershell

docker exec -it RedisCache redis-cli
auth 123456
ping
Redis CLI

Install Redis in Dotnetcore

Install-Package Microsoft.Extensions.Caching.StackExchangeRedis -Version 5.0.1
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = "localhost:32768,password=redispw";
options.InstanceName = "";
});

Create Model

public class Movie
{
public int Id { get; set; }

public string? Title { get; set; }

public string? Genre { get; set; }

public DateTime ReleaseDate { get; set; }
}

Create Controller

namespace RedisCacheSystem.Controllers
{
[ApiController]
[Route("Api/Movie")]
public class MovieController : ControllerBase
{

}
}

Save into Redis Cache

private readonly IDistributedCache _cache;

public MovieController(IDistributedCache cache)
{
_cache = cache;
}

[HttpPost("CreateMovie")]
public async Task<IActionResult> CreateMovie(Movie model)
{
var content = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(model));

await _cache.SetAsync("Movie_"+model.Id, content,new DistributedCacheEntryOptions{SlidingExpiration = TimeSpan.FromDays(1)});
return Ok();
}
Swagger Api
        [HttpPost]
public async Task<ActionResult<Movie>> PostMovie(Movie movie)
{
var content = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(movie));
await _cache.SetAsync(movie.Id , content , new DistributedCacheEntryOptions { SlidingExpiration = TimeSpan.FromDays(1) });
var result = await _movieService.PostMovie(movie);
return CreatedAtAction(nameof(GetMovie), new { id = result.Id }, result);
}

Controller Source

 [Route("api/[controller]")]
[ApiController]
public class MoviesController : ControllerBase
{
private readonly IMovieService _movieService;
private readonly IDistributedCache _cache;

public MoviesController(IMovieService movieService, IDistributedCache cache)
{
this._movieService = movieService;
this._cache = cache;
}

// GET: api/Movies
/// <summary>
/// Creates a TodoItem.
/// </summary>
/// <remarks>
/// Sample request:
///
/// POST /Todo
/// {
/// "id": 1,
/// "name": "Item1",
/// "isComplete": true
/// }
///
/// </remarks>
/// <param name="name"></param>
/// <returns>A newly created TodoItem</returns>
/// <response code="201">Returns the newly created item</response>
/// <response code="400">If the item is null</response>
[HttpGet]
[Route("GetMovies")]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status100Continue)]
public async Task<ActionResult<IEnumerable<Movie>>> GetMovies()
{
var list = await _cache.GetAsync("All");
if (list!=null)
{
return Ok(JsonSerializer.Deserialize<List<Movie>>(list));
}
var result= await _movieService.GetMovies();
var content = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(result));
await _cache.SetAsync("All", content, new DistributedCacheEntryOptions { SlidingExpiration = TimeSpan.FromDays(1) });
if (result == null)
{
return NotFound();
}
return Ok(result);
}

// GET: api/Movies/5
[HttpGet("{id}")]
public async Task<ActionResult<Movie>> GetMovie(int id)
{
var movie = await _cache.GetAsync(id.ToString());
if (movie != null)
{
return Ok(JsonSerializer.Deserialize<Movie>(movie));
}
var result = await _movieService.GetMovie(id);
var content = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(result));
await _cache.SetAsync(id.ToString(), content, new DistributedCacheEntryOptions { SlidingExpiration = TimeSpan.FromDays(1) });

if (result == null)
{
return NotFound();
}
return Ok(result);
}

// POST: api/Movies
[HttpPost]
public async Task<ActionResult<Movie>> PostMovie(Movie movie)
{
var content = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(movie));
await _cache.SetAsync(movie.Title, content , new DistributedCacheEntryOptions { SlidingExpiration = TimeSpan.FromDays(1) });
var result = await _movieService.PostMovie(movie);
return CreatedAtAction(nameof(GetMovie), new { id = result.Id }, result);
}

// PUT: api/Movies/5
[HttpPut("{id}")]
public async Task<IActionResult> PutMovie(int id, Movie movie)
{
var result = await _movieService.PutMovie(id,movie);
if (result.Status == StatusCodes.Status400BadRequest)
{
return BadRequest();
}
if (result.Status == StatusCodes.Status404NotFound)
{
return NotFound();
}

return NoContent();
}

// DELETE: api/Movies/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteMovie(int id)
{
var result = await _movieService.DeleteMovie(id);
if (result == null)
{
return NotFound();
}
await _cache.RemoveAsync(id.ToString());
return NoContent();
}


/*
You have predefined methods for most common status codes.
Ok(result) returns 200 with response
CreatedAtRoute returns 201 + new resource URL
NotFound returns 404
BadRequest returns 400 etc.
*/
}
}

Result

Redis is an open source in-memory data store, which is often used as a distributed cache. You can configure an Azure Redis Cache for an Azure-hosted ASP.NET Core app, and use an Azure Redis Cache for local development. An app configures the cache implementation using a RedisCache instance (AddStackExchangeRedisCache).

--

--

Tohid haghighi
Tohid haghighi

Written by Tohid haghighi

Full-Stack Developer | C# | .NET Core | Vuejs | TDD | Javascript

No responses yet