How to implement Azure Cache for Redis in a .NET Core Web API?

In this .NET tutorial, I will teach you how to implement Azure Cache for Redis / Azure Redis Cache in your .NET Core Web API. Redis is the perfect choice if you want a distributed cache solution for your application.

Why should you implement a cache solution? Are you struggling to keep up with incoming requests to your API? Is your API working to serve the same request over and over again fast enough? Or are you just planning to integrate a cache in your API before any of the before mentioned will happen? Redis is a perfect choice but it can be challenging to host yourself.

Caching has become a very popular tool to implement in applications to serve requests faster. By implementing a cache you will be able to improve the overall performance and scalability of your application. Caching will improve the user experience by making the application serve requests in a snap resulting in a better experience.

By the end of this tutorial, you will know how to set up and configure Azure Redis Cache and how you can use it in combination with your ASP.NET Core Web API easily. If you are ready, then let's dive in!

Below is a link for the service description at Microsoft.

Azure Cache for Redis | Microsoft Azure
Power fast, scalable applications with Azure Cache for Redis, cache databases as a service with fully managed, open-source-compatible in-memory data storing service.

Prerequisites

In order to follow along with me in this tutorial, you will need the following tools and services.

  • Visual Studio 2022.
  • .NET 7 SDK installed (.NET 6 SDK will also do the job).
  • An Azure Account with an active subscription.
  • Intermediate .NET and C# knowledge.

What are we going to cover in this Azure Redis Cache Tutorial?

Before we start, let's cover what we will go through in this Azure Redis Cache guide for .NET Core. You can expect the following.

  • An introduction to what a cache is and different types of caches.
  • Why you should use a cache in your application?
  • High-Level View of Redis Cache.
  • How to configure an Azure Cache for Redis in the cloud. (Redis cache in the cloud)
  • How to implement Azure Redis Cache in a simple .NET Core Web API. You can use .NEt 6 and 7 for this tutorial.

What is a Cache?

Maybe you already know what a cache is, then you can skip this part. For those of you who would like a refresher, keep reading. I promise no long in-depth description, only a high-level view of what a cache is.

You can think of a cache as a temporary place to store the data (without persisting them). A cache will be a type of memory storage and the reason for that is that memory often is insanely fast. This is the actual reason that we can improve the performance and avoid pushing our database to its knees.

Let's have a look at a scenario, to give you a better understanding.

azure cache, azure redis cache, azure cache for redis, api requests
Scenario 1 - Requests without a cache

In the above image (Scenario 1) we have no cache and the API will translate all incoming requests and ask the database for data. This will make our database take a lot of hits because it has to respond to every request when a client asks for a resource.

Imagine having thousands of users requesting resources at the same time, that would cause the performance of the application to be slow. Let's take a look at what it looks like if we apply a cache.

azure cache, azure redis cache, azure cache for redis, api requests
Scenario 2 - Requests with a cache

In the image above (Scenario 2) we have a cache to take some of the hits from our users. If the API is able to "see" that the request matches the same one it just got before, it will forward the request to the cache instead of the database.

This will make the first request slower because the data has to be loaded from the database into the cache, but then it will be fast! The next request for the same resource will be delivered within a few milliseconds because the response is stored within the memory and no database interaction has to be done.

What Type of Caches do we have?

I can't tell for other programming languages as I am mostly into .NET. When you develop applications using the .NET Framework, you got two options: In-Memory Caching, and Distributed Caching.

In-Memory Cache

An In-Memory cache is storing its data on the same server as the one handling the requests. This will often be the API server, which sometimes also is the one running the database.

When a new request is arriving we will fetch the cache data from the local machine and deliver it to the client. If we got a lot of requests and the API + database are some huge bastards, I would not recommend placing the cache onto the same resource server. This is where distributed caching comes into the picture.

If you would like to know more about how to implement an in-memory cache, you can take a look at my in-memory tutorial for .NET 6 below. Bonus - you will learn how to implement it using the decorator pattern.

How to add In-Memory Caching to .NET 6 Web API
Learn how to add In-Memory caching 💾 to your .NET Core Web API using the decorator pattern with a few lines of code in this step-by-step tutorial

Distributed Cache

distributed cache, implement distributed cache .net, azure distributed cache, azure cache for redis, azure redis cache
Distributed Cache

In the image above I have created a very simple illustration of what a distributed cache is. As you can see there are multiple application servers and that is because a distributed cache allows for scaling because each app server is capable of retrieving data from the same cache. Below are some key-take-away points.

  • A distributed cache is running in the cloud or on-premise and makes it possible for data to be stored between multiple servers.
  • Because it's located away from the application, we can scale it to follow the demand of our application up and down. This is often done when you work with multi-tenancy because a lot of users are accessing their details often.
  • In an environment with a load balancer in front of our app servers we can restart a server without any issues because the two other servers running our application will have the same functionality and data in the cache + database will be consistent across the servers. Our users will not experience any drops in connectivity and can continue to use our application, while we fix one server.

For this tutorial, we will (as you might have guessed) use Redis as our distributed cache solution. Redis is probably the most popular cache solution (maybe because it's open-source) and can scale and improve the performance of an application like no one else. Let's take a brief introduction to Redis.

High-Level View of Redis Cache

Before we start configuring Azure, let's have a quick look at what Redis is.

Redis | The Real-time Data Platform
Developers love Redis. Unlock the full potential of the Redis database with Redis Enterprise and start building blazing fast apps.

Redis short for Remote Dictionary Server is an in-memory data store used by millions of developers as a database, cache, streaming engine, and message broker. It uses a NoSQL Key/value store to cache data a deliver a quick response of data.

Redis is storing data in memory instead of a traditional disk like an HDD or SSD (Solid-State Drive). Because of this, Redis delivers unparalleled speed, reliability, and performance to its users. Do we love anything else? I don't think so!

We use Redis to store often-accessed data and static data in the memory to unload the pressure on our database. Redis got a lot of options to list, set, hash, stream, etc... data inside an application, which also makes it so popular, because it got a lot of use cases. Below are some use cases.

  • Real-Time Data Store - You can utilize the in-memory data structures to enable building data infrastructure for real-time applications that require low latency and high throughput.
  • Caching & Session Storage - Because of the speed of Redis it is ideal for caching database queries, complex computations, API calls, and session states. What we will be doing for this tutorial.
  • Streaming & Messaging - Stream is a data type in Redis, that enables high-rate data ingestion, messaging, event sourcing, and notifications.

Enough theory! Let's get to the fun part and get our hands dirty.

Azure Configuration

Configure Azure to use the Redis Caching Service

Configure an Azure Cache for Redis

Head over to portal.azure.com and sign in with your Azure Account and make sure you got an active subscription you can use at that account.

In the search field at the top of the dashboard, search for Azure Cache for Redis and select it.

azure cache for redis, azure redis cache
Search for Azure Cache for Redis

Now click on + Create at the new page that just opened. This will open a new page where you can fill out details about your Azure Cache for Redis. You can select the options as I have done below and click on the Review + create button. The rest of the settings are optional and not needed for this tutorial.

redis cache, new azure redis cache, azure redis cache, azure cache for redis
New Redis Cache at Azure

For the Cache type, I have selected Basic C0. This is currently the cheapest option and will cost you around $16 /month ~ $0.022 /hour - which is fair pricing as Azure got the full responsibility of configuration, domain, hosting, etc... You can read more about the pricing here.

review + create azure redis cache, deploy azure redis cache, redish cache azure
Review + create a new Redis Cache at Azure

When you are ready, simply hit the Create button to deploy your new Azure Redis Cache. This should bring you back to the page where you can see an overview of your Azure Redis Cache being deployed.

azure redis cache, azure cache for redis, redis deployment, azure redis cache deployment
Azure Redis Cache - Deployment is in progress

The deployment of the new Redis service can take some time - my deployment took roughly 15 minutes. Now is a good time to go grab a cup of coffee or tea while you wait. Once the deployment has been completed, you should see a page like the one I got below.

azure redis cache deployment, redis cache deployment complete, azure deployment
Azure Redis Cache Deployment is Complete

Click on the button Go to resource to continue.

Grab the Access keys for the Azure Redis Cache Service

In the menu on your left, head to the page named Access keys. It's located below the Settings heading in the menu.

azure redis cache, azure access keys, StackExchange.Redis, redis connectionstring, azure connectionstring
Azure Redis Cache Access Keys

Copy the Primary connection string (StackExchange.Redis) value and store it in a secret place, we will use it in a moment to connect our .NET Web API to the Azure Redis Cache Service.

That's it for Azure. We are done with the configuration and can now continue with the development of our .NET Web API where we will be implementing a service to talk with our Redis Cache before we ask the database for any data.

Application Development

Time for implementation of Azure Redis Cache in our .NET Web API

Getting Started

By the end, I will post a link to the repository for the full solution. Before I do that, I will cover each step I do in order to communicate with the Azure Redis Cache Service we just created.

The first thing you have to do is open up Visual Studio 2022 (or newer) and create a new .NET Core Web API (or simply follow along with your existing solution).

I have named my project AzureRedisCacheApi - you can name yours what you prefer. Below are the additional settings for the project I have created.

create new project in visual studio, additional information visual studio
Additional Project Information

For simplicity, I will not be implementing the solution using a fancy architecture and multiple layers to separate logic from the API, etc... Everything will be placed within the same solution, and the project structure will look like the following:

Implement Azure Redis Cache in .NET Web API

The final result will serve some books about software development from our cache and MS SQL Database. The first thing we will do is the installation of any required NuGet package in the project.

Install NuGet Packages

Our API will need a few packages installed in order to work. Below are the commands for the packages. Run each line inside the Package Manager Console and rebuild the project.

Install-Package Microsoft.EntityFrameworkCore
Install-Package Microsoft.EntityFrameworkCore.Tools
Install-Package Microsoft.EntityFrameworkCore.Design
Install-Package Microsoft.EntityFrameworkCore.SqlServer
Install-Package Microsoft.Extensions.Caching.StackExchangeRedis
Install-Package StackExchange.Redis

By default packages for Swagger / OpenAPI will be installed for us, when we create the API project. If you want to extend the documentation for your .NET Web API, you can check out my tutorial about creating API documentation using Swagger and ReDoc below.

How to make API documentation using Swagger and ReDoc
In this tutorial, I will show you how to generate API documentation using Swagger and ReDoc for your ASP.NET Core Web API (.NET 6)

Add Entities

To do this, we have to define what a book looks like in the real world. Let's create a new entity for a Book. The entity classes will be stored in a folder named Entities. Create a folder named Entities at the root of your API project and add a new class named Book.cs with the following properties:

namespace AzureRedisCacheApi.Entities
{
	public class Book
	{
		public int Id { get; set; }
		public string Title { get; set; }
		public string Description { get; set; }
		public string Author { get; set; }
		public string Publisher { get; set; }
		public string Language { get; set; }
		public string Edition { get; set; }
		public DateTime Published { get; set; }
        public string ISBN10 { get; set; }
        public string ISBN13 { get; set; }
		public double Rating { get; set; }
    }
}

The above code will define a basic book. The ideal application will move the data into separate tables in order to comply with 3NF.

Add Persistence

An API without any data is not much fun. Instead of us adding data to the API every time we make changes, etc... let's add a database seeder that will add a few books for us to request from the API. The books will later be stored within the Redis Cache too.

Create a new folder named Persistence at the root of your project and add a child folder named Seed inside the Persistence folder. Inside the Seed folder, create a new class named DbInitializer.cs with the following code inside. I will explain below:

using AzureRedisCacheApi.Entities;
using Microsoft.EntityFrameworkCore;

namespace AzureRedisCacheApi.Persistence.Seed
{
	public static class DbInitializer
	{
		public static void Seed(this ModelBuilder modelBuilder)
		{
			modelBuilder.Entity<Book>(x =>
			{
				x.HasData(new Book
				{
					Id = 1,
					Title = "Clean Code: A Handbook of Agile Software Craftsmanship",
					Description = "Even bad code can function. But if code isn’t clean, it can bring a development organization to its knees. Every year, countless hours and significant resources are lost because of poorly written code. But it doesn’t have to be that way.",
					Author = "Robert C. Martin (Author)",
					Publisher = "Pearson",
					Language = "English",
					Edition = "1st",
					ISBN10 = "9780132350884",
					ISBN13 = "978-0132350884",
					Published = DateTime.Parse("Aug 1, 2008"),
					Rating = 4.4
				});
				
				x.HasData(new Book
				{
					Id = 2,
					Title = "Design Patterns: Elements of Reusable Object-Oriented Software",
					Description = "Capturing a wealth of experience about the design of object-oriented software, four top-notch designers present a catalog of simple and succinct solutions to commonly occurring design problems. Previously undocumented, these 23 patterns allow designers to create more flexible, elegant, and ultimately reusable designs without having to rediscover the design solutions themselves.",
					Author = "Erich Gamma (Author), Richard Helm (Author), Ralph Johnson (Author), John Vlissides (Author), Grady Booch (Foreword)",
					Publisher = "Pearson",
					Language = "English",
					Edition = "1st",
					ISBN10 = "0201633612",
					ISBN13 = "978-0201633610",
					Published = DateTime.Parse("Oct 31, 1994"),
					Rating = 4.2
				});
				
				x.HasData(new Book
				{
					Id = 3,
					Title = "Head First Design Patterns: A Brain-Friendly Guide",
					Description = "At any given moment, someone struggles with the same software design problems you have. And, chances are, someone else has already solved your problem. This edition of Head First Design Patterns—now updated for Java 8—shows you the tried-and-true, road-tested patterns used by developers to create functional, elegant, reusable, and flexible software.",
					Author = "Eric Freeman (Author), Bert Bates (Author), Kathy Sierra (Author), Elisabeth Robson (Author)",
					Publisher = "O'Reilly Media",
					Language = "English",
					Edition = "1st",
					ISBN10 = "9780596007126",
					ISBN13 = "978-0596007126",
					Published = DateTime.Parse("Oct 1, 2004"),
					Rating = 4.7
				});
				
				x.HasData(new Book
				{
					Id = 4,
					Title = "The Pragmatic Programmer: From Journeyman to Master",
					Description = "Ward Cunningham Straight from the programming trenches, The Pragmatic Programmer cuts through the increasing specialization and technicalities of modern software development to examine the core process--taking a requirement and producing working, maintainable code that delights its users.",
					Author = "Andrew Hunt (Author), David Thomas (Author)",
					Publisher = "Addison-Wesley Professional",
					Language = "English",
					Edition = "1st",
					ISBN10 = "9780201616224",
					ISBN13 = "978-0201616224",
					Published = DateTime.Parse("Oct 30, 1999"),
					Rating = 4.8
				});
			});
		}
	}
}

The code above contains a static class with an extension method Seed(this ModelBuilder modelBuilder) for the ModelBuilder class. The Seed class got 4 books that will be seeded into the database during the migration of the database to the newest available version.

To use these seed data, we have to create a new Database Context using Entity Framework Core. Create a new class named AppDbContext.cs inside the Persistence folder. The AppDbContext.cs will look like the following, which I will explain below.

using AzureRedisCacheApi.Entities;
using AzureRedisCacheApi.Persistence.Seed;
using Microsoft.EntityFrameworkCore;

namespace AzureRedisCacheApi.Persistence
{
	public class AppDbContext : DbContext
	{
		public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
		{
		}

		// Add the books entity to be added in our database
		public DbSet<Book> Books { get; set; }

		protected override void OnModelCreating(ModelBuilder modelBuilder)
		{
			// Seed database with new data if its not already present
			modelBuilder.Seed();

			base.OnModelCreating(modelBuilder);
		}
	}
}

In the AppDbContext class above we:

  • Derive from the DbContext class and create a new constructor where we override DbContext.
  • Register our Book entity, so that we can use it with LINQ and it will be created in our database using the code-first approach.
  • Finally, we Seed the database with the DbInitializer class we created before.

To follow along and see what changes I have made so far, you can check the commit for this point here: Add Entity, Database, and DB Initializer.

Register Services

I like to keep my Program.cs file is clean, but we have to register our services. Instead of cluttering up our Program.cs file when registering services in the service container, let's create an extension for IServiceCollection that we can register in Program.cs file.

Create a new folder named Services and add a new file named Startup.cs inside the folder. The Startup.cs file is a static class we will use to register all services and application services for the service container and HTTP Request Pipeline. Add the following code inside:

using AzureRedisCacheApi.Persistence;
using Microsoft.EntityFrameworkCore;

namespace AzureRedisCacheApi.Services
{
	public static class Startup
	{
		public static IServiceCollection AddServices(this IServiceCollection services, IConfiguration configuration)
		{
			services.AddDatabase(configuration);
			services.AddControllers();
			services.AddEndpointsApiExplorer();
			services.AddSwaggerGen();
			return services;
		}

		public static IServiceCollection AddDatabase(this IServiceCollection services, IConfiguration configuration)
		{
			services.AddDbContext<AppDbContext>(options =>
				options.UseSqlServer(configuration.GetConnectionString("Default")));

			return services;
		}

		public static IApplicationBuilder AddApplication(this IApplicationBuilder app)
		{
			app.UseSwagger();
			app.UseSwaggerUI();
			app.UseHttpsRedirection();
			app.UseAuthorization();

			return app;
		}
	}
}

As you can see I have moved most of the registrations from Program.cs to this Startup.cs class. This means we gotta do some housekeeping in Program.cs - let's head there.

Because I am lazy and I would like to migrate the database automatically every time the application boots, I will implement an automatic migration functionality. You can read more in-depth about how this is done in the article below.

.NET 6 - Perform Automatic EF Core Migrations at startup
Learn how to run automatic EF Core migrations at startup of your .NET application. Only two steps and you are never doing a manual migration.

The updated Program.cs file now looks like the following:

using AzureRedisCacheApi.Persistence;
using AzureRedisCacheApi.Services;
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddServices(builder.Configuration);

var app = builder.Build();

// Configure the HTTP request pipeline.
// Seed Database
using (var scope = app.Services.CreateScope())
{
	var dbContext = scope.ServiceProvider
		.GetRequiredService<AppDbContext>();

	dbContext.Database.Migrate();
}

app.AddApplication();
app.MapControllers();
app.Run();

The AddDbContext method is expecting IConfiguration to contain a key/value for a connection string named Default, because I gave it that name when registering the database context in Startup.cs. Let's add that inside appsettings.json to avoid any errors.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "Default": "Server=localhosts;Database=AzureRedisCacheDemoApi;Trusted_Connection=True;"
  }
}

You should of course change the connection string to match your database.

Create Migration for Database and Seed data

Let's create a migration for our database and seed data. Open up Package Manager Console and enter the following command to create a new migration and place the migrations in the persistence folder.

Add-Migration InitialMigration -o Persistence/Migrations

This should result in the following:

PM> Add-Migration InitialMigration -o Persistence/Migrations
Build started...
Build succeeded.
To undo this action, use Remove-Migration.
PM> 

Let's start up the application to make sure that the database is created in our SQL Server. At startup, the terminal should show you the migration process and inside the database itself, you should now see the following.

database, ms sql server, ssms, database migration
Successful Database Migration and Update

To see the changes I made so far, you can check the latest commit for the demo here: Added service registration, migrations, and update DB context.

Add Book Repository

Now that we got some books available in our database, let's create a repository to serve the books to our controller.

Create a new child folder inside the Services folder named Repositories. Now add a new class inside Repositories named IBookRepository.cs and add the following code inside it:

using AzureRedisCacheApi.Entities;
using AzureRedisCacheApi.Persistence;

namespace AzureRedisCacheApi.Services.Repositories
{
	public interface IBookRepository
	{
		Task<IReadOnlyList<Book>> GetBooksAsync();
		Task<Book> GetBookAsync(int bookId);
		Task<Book> AddBookAsync(Book book);
		Task<Book> UpdateBookAsync(Book book);
		Task<bool> DeleteBookAsync(int bookId);
	}
}

As you can see this is basic CRUD functionality and it will help us create a standard REST API in a moment. If you would like an in-depth tutorial about creating a REST API, you can check out my article below.

How to build a RESTful Web API using .NET Core and EF Core
Learn how to build your own RESTful Web API with ASP.NET Core and Entity Framework Core (.NET 6) with auto data seeding to MS SQL.

Let's give these methods some life by implementing the logic behind them. Create a new file in the Repositories folder named BookRepository.cs and add the following code inside it.

using AzureRedisCacheApi.Entities;
using AzureRedisCacheApi.Persistence;
using Microsoft.EntityFrameworkCore;

namespace AzureRedisCacheApi.Services.Repositories
{
	public class BookRepository : IBookRepository
	{
		private readonly AppDbContext _appDbContext;

		public BookRepository(AppDbContext appDbContext)
		{
			_appDbContext = appDbContext;
		}

		public async Task<Book> AddBookAsync(Book book)
		{
			await _appDbContext.Books.AddAsync(book);
			await _appDbContext.SaveChangesAsync();
			return book;
		}

		public async Task<bool> DeleteBookAsync(int bookId)
		{
			var book = await GetBookAsync(bookId);
			var deleteResult = _appDbContext.Books.Remove(book);
			await _appDbContext.SaveChangesAsync();
			return deleteResult != null ? true : false;
		}

		public async Task<Book> GetBookAsync(int bookId)
		{
			return await _appDbContext.Books.FirstOrDefaultAsync(x => x.Id == bookId);
		}

		public async Task<IReadOnlyList<Book>> GetBooksAsync()
		{
			return await _appDbContext.Books.ToListAsync();
		}

		public async Task<Book> UpdateBookAsync(Book book)
		{
			var updateResult = _appDbContext.Books.Update(book);
			await _appDbContext.SaveChangesAsync();
			return updateResult.Entity;
		}
	}
}

What happens in the code above?

  • We inject the database context so that our repository is capable of communicating with the database.
  • We implement the methods we inherited from IBookRepository and add the logic to make them work.

Now we have to register the repository as a transient in our Startup.cs file in the Services folder. This is because we would like to inject the repository into a book controller in a moment.

In the AddServices(...) method, just below our database registration, we will register the Transient for our book repository.

using AzureRedisCacheApi.Persistence;
using AzureRedisCacheApi.Services.Repositories;
using Microsoft.EntityFrameworkCore;

namespace AzureRedisCacheApi.Services
{
	public static class Startup
	{
		public static IServiceCollection AddServices(this IServiceCollection services, IConfiguration configuration)
		{
			services.AddDatabase(configuration);
			services.AddTransient<IBookRepository, BookRepository>();
			services.AddControllers();
			services.AddEndpointsApiExplorer();
			services.AddSwaggerGen();
			return services;
		}

		...
	}
}

We have now registered the book repository in our service container. Let's use it in the book controller to retrieve some books.

🤓
TIP - I would recommend handling all errors using a global exception handler and throwing the NotFound Exceptions in the repository. This would remove the requirement for you to check for null values in the controller. If you would like to know how to implement global exception handling, you can check out my article below.
How to add Global Exception Handling in .NET 6 and 7
Handle exceptions efficiently with Global Exception Handling in .NET with this step-by-step guide. Full source code is included for free.

Add Book Controller

This will start as a very simple implementation of our book controller and serve the book repository functionality for the client/user.

Create a new controller named BookController.cs and remove the default one named WeatherForecastController.cs alongside its class WeatherForecast.cs they are unnecessary for this tutorial.

Inside BookController.cs add the following code.

using AzureRedisCacheApi.Entities;
using AzureRedisCacheApi.Services.Repositories;
using Microsoft.AspNetCore.Mvc;

namespace AzureRedisCacheApi.Controllers
{
	[Route("api/[controller]")]
	[ApiController]
	public class BookController : ControllerBase
	{
		private readonly IBookRepository _bookRepo;

		public BookController(IBookRepository bookRepo)
		{
			_bookRepo = bookRepo;
		}

		[HttpGet("get")]
		public async Task<IActionResult> GetAllAsync()
		{
			var books = await _bookRepo.GetBooksAsync();
			return Ok(books);
		}

		[HttpGet("get/{id}")]
		public async Task<IActionResult> GetSingleAsync(int id)
		{
			var book = await _bookRepo.GetBookAsync(id);
			return Ok(book);
		}

		[HttpPost("add")]
		public async Task<IActionResult> AddBookAsync(Book book)
		{
			var result = await _bookRepo.AddBookAsync(book);
			return Ok(result);
		}

		[HttpPut("update")]
		public async Task<IActionResult> UpdateBookAsync(Book book)
		{
			var result = await _bookRepo.UpdateBookAsync(book);
			return Ok(result);
		}

		[HttpDelete("delete/{id}")]
		public async Task<bool> DeleteBookAsync(int id)
		{
			return await _bookRepo.DeleteBookAsync(id);
		}
	}
}

As you can see it's a simple controller for now that will just serve the books to and from our repository that will take care of the database operations. Great, let's fire it up and see if we can retrieve some books!

swagger, get all books, get, httpget
Swagger Test for Getting all Books from API without Redis Cache

Awesome! We can get our books and the database got hit by the request because we currently do not have any caching enabled. Let's move on and add some distributed Azure Redis caching to our .NET Web API.

Add Azure Redis Caching (Distributed Caching)

Now for the fun part, you are here for. Now we will add Distributed caching to our application to serve the requests from a cache and not the database every time.

Add Primary Connection String from Access Keys

Now it's time for configuring the connection string in our application. You can set the connection string inside usersecrets.json or appsettings.json. For this tutorial, I have added an extra connection string property with the primary connection string from my Azure Redis Cache Service. It looks like this in appsettings.json.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "Default": "Data Source=localhost;Initial Catalog=AzureRedisCacheApi;Integrated Security=True;MultipleActiveResultSets=True;TrustServerCertificate=True;",
    "AzureRedisUrl": "<YOUR-REDIS-URL>:6380,password=<YOUR-PASSWORD>,ssl=True,abortConnect=False"
  }
}

Register Caching Service in Startup

With the connection string in place, let's register our caching service with two options. Open Startup.cs inside the Services folder and add another IServiceCollection named AddCaching. It looks like this:

public static IServiceCollection AddCaching(this IServiceCollection services, IConfiguration configuration)
{
	services.AddStackExchangeRedisCache(options =>
	{
		options.Configuration = configuration.GetConnectionString("AzureRedisUrl");
		options.InstanceName = "master";
	});
	return services;
}

In the AddServices method above we will register this new service just below the database registration, just like I have done below.

public static IServiceCollection AddServices(this IServiceCollection services, IConfiguration configuration)
{
	services.AddDatabase(configuration);
	services.AddCaching(configuration);
	services.AddTransient<IBookRepository, BookRepository>();
	services.AddControllers();
	services.AddEndpointsApiExplorer();
	services.AddSwaggerGen();
	return services;
}

Now the Redis Cache has been registered in our service container with the connection string from our configuration.

Update Book Controller to use caching

Before I show you how to implement this functionality I would like to give you a short theory session about GetAsync and SetAsync.

Continue reading for free

Sign up to read this post and all other free TWC member only posts. Yes it's totally free and I promise no spam! You can unsubscribe or modify what kind of notifications you get from me at any time.
You've successfully subscribed to Tech with Christian
Great! Next, complete checkout to get full access to all premium content.
Error! Could not sign up. invalid link.
Welcome back! You've successfully signed in.
Error! Could not sign in. Please try again.
Success! Your account is fully activated, you now have access to all content.
Error! Stripe checkout failed.
Success! Your billing info is updated.
Error! Billing info update failed.