Skip to content

Commit 44d62db

Browse files
Add Azure Redis Caching
Implemented Azure Redis Cache in project with an instance record for the keys we add to the Redis Store/Database.
1 parent 5b9d964 commit 44d62db

File tree

4 files changed

+181
-1
lines changed

4 files changed

+181
-1
lines changed

AzureRedisCacheApi/AzureRedisCacheApi.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<PropertyGroup>
44
<TargetFramework>net7.0</TargetFramework>
55
<ImplicitUsings>enable</ImplicitUsings>
6+
<UserSecretsId>924d2484-033f-4b67-8e62-95631b53ecb4</UserSecretsId>
67
</PropertyGroup>
78

89
<ItemGroup>
@@ -18,6 +19,8 @@
1819
<PrivateAssets>all</PrivateAssets>
1920
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
2021
</PackageReference>
22+
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="7.0.2" />
23+
<PackageReference Include="StackExchange.Redis" Version="2.6.90" />
2124
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
2225
</ItemGroup>
2326

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
using AzureRedisCacheApi.Entities;
2+
using AzureRedisCacheApi.Services.Repositories;
3+
using Microsoft.AspNetCore.Mvc;
4+
using Microsoft.Extensions.Caching.Distributed;
5+
using System.Text;
6+
using System.Text.Json;
7+
8+
namespace AzureRedisCacheApi.Controllers
9+
{
10+
[Route("api/[controller]")]
11+
[ApiController]
12+
public class BookController : ControllerBase
13+
{
14+
private readonly IBookRepository _bookRepo;
15+
private readonly IDistributedCache _redis;
16+
17+
public BookController(
18+
IBookRepository bookRepo,
19+
IDistributedCache redis)
20+
{
21+
_bookRepo = bookRepo;
22+
_redis = redis;
23+
}
24+
25+
[HttpGet("get")]
26+
public async Task<IActionResult> GetAllAsync()
27+
{
28+
// Retrieve any books stored in the Redis cache
29+
byte[] booksInRedis = await _redis.GetAsync("books");
30+
31+
// Check that we actually got some books in return from the Redis cache
32+
if ((booksInRedis?.Count() ?? 0) > 0) // Amount of books is larger than 0?
33+
{
34+
// Get the books in redis as a string
35+
string bookString = Encoding.UTF8.GetString(booksInRedis);
36+
37+
// Deserialize the string into a list of books
38+
List<Book> booksFromRedis = JsonSerializer.Deserialize<List<Book>>(bookString);
39+
40+
// Return the books
41+
return Ok(new
42+
{
43+
DataFromRedis = true,
44+
Data = booksFromRedis
45+
});
46+
}
47+
48+
// We did not have any books in our Redis Cache. Let's add some books
49+
50+
// First we will get all of our books
51+
IReadOnlyList<Book> booksFromDb = await _bookRepo.GetBooksAsync();
52+
53+
// Then serialize the books into a string
54+
string serializedBooks = JsonSerializer.Serialize(booksFromDb);
55+
56+
// Convert the serialized books into a byte array
57+
byte[] booksToCache = Encoding.UTF8.GetBytes(serializedBooks);
58+
59+
// Configure Expiration for Caching
60+
DistributedCacheEntryOptions expiration = new DistributedCacheEntryOptions
61+
{
62+
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(8),
63+
SlidingExpiration = TimeSpan.FromMinutes(5),
64+
};
65+
66+
// Store the books into the Redis Cache
67+
await _redis.SetAsync("books", booksToCache, expiration);
68+
69+
// Return the books
70+
return Ok(new
71+
{
72+
DataFromRedis = false,
73+
Data = booksFromDb
74+
});
75+
}
76+
77+
[HttpGet("get/{id}")]
78+
public async Task<IActionResult> GetSingleAsync(int id)
79+
{
80+
// Retrieve any books stored in the Redis cache
81+
byte[] booksInRedis = await _redis.GetAsync("books");
82+
83+
// Check that we actually got some books in return from the Redis cache
84+
if ((booksInRedis?.Count() ?? 0) > 0)
85+
{
86+
// Decode and serialize into list of books
87+
string bookString = Encoding.UTF8.GetString(booksInRedis);
88+
List<Book> booksFromRedis = JsonSerializer.Deserialize<List<Book>>(bookString);
89+
90+
// Use LINQ to get the book we are looking for
91+
Book bookFromRedis = booksFromRedis.Where(x => x.Id == id).FirstOrDefault();
92+
93+
if (bookFromRedis == null)
94+
{
95+
return NotFound();
96+
}
97+
98+
// Return the book
99+
return Ok(new
100+
{
101+
DataFromRedis = true,
102+
Data = bookFromRedis
103+
});
104+
}
105+
106+
// We did not get a book from the Redis Cache, let's retrieve it from our database
107+
Book book = await _bookRepo.GetBookAsync(id);
108+
if (book != null)
109+
{
110+
// Return the book we got from our database
111+
return Ok(new
112+
{
113+
DataFromRedis = false,
114+
Data = book
115+
});
116+
}
117+
118+
// No book with the given ID was able to be looked up
119+
return NotFound();
120+
121+
}
122+
123+
[HttpPost("add")]
124+
public async Task<IActionResult> AddBookAsync(Book book)
125+
{
126+
// Add the new book to our database
127+
await _bookRepo.AddBookAsync(book);
128+
129+
// Clear the cache
130+
await _redis.RemoveAsync("books");
131+
132+
// Return the created book
133+
return Ok(new
134+
{
135+
DataFromRedis = false,
136+
Data = book
137+
});
138+
}
139+
140+
[HttpPut("update")]
141+
public async Task<IActionResult> UpdateBookAsync(Book book)
142+
{
143+
// Update the book in our database
144+
await _bookRepo.UpdateBookAsync(book);
145+
146+
// Clear the cache
147+
await _redis.RemoveAsync("books");
148+
149+
// Return the updated book
150+
return Ok(new
151+
{
152+
DataFromRedis = false,
153+
Data = book
154+
});
155+
}
156+
157+
[HttpDelete("delete/{id}")]
158+
public async Task<bool> DeleteBookAsync(int id)
159+
{
160+
return await _bookRepo.DeleteBookAsync(id);
161+
}
162+
}
163+
}

AzureRedisCacheApi/Services/Startup.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using AzureRedisCacheApi.Persistence;
2+
using AzureRedisCacheApi.Services.Repositories;
23
using Microsoft.EntityFrameworkCore;
34

45
namespace AzureRedisCacheApi.Services
@@ -8,6 +9,8 @@ public static class Startup
89
public static IServiceCollection AddServices(this IServiceCollection services, IConfiguration configuration)
910
{
1011
services.AddDatabase(configuration);
12+
services.AddCaching(configuration);
13+
services.AddTransient<IBookRepository, BookRepository>();
1114
services.AddControllers();
1215
services.AddEndpointsApiExplorer();
1316
services.AddSwaggerGen();
@@ -22,6 +25,16 @@ public static IServiceCollection AddDatabase(this IServiceCollection services, I
2225
return services;
2326
}
2427

28+
public static IServiceCollection AddCaching(this IServiceCollection services, IConfiguration configuration)
29+
{
30+
services.AddStackExchangeRedisCache(options =>
31+
{
32+
options.Configuration = configuration.GetConnectionString("AzureRedisUrl");
33+
options.InstanceName = "master";
34+
});
35+
return services;
36+
}
37+
2538
public static IApplicationBuilder AddApplication(this IApplicationBuilder app)
2639
{
2740
app.UseSwagger();

AzureRedisCacheApi/appsettings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
},
88
"AllowedHosts": "*",
99
"ConnectionStrings": {
10-
"Default": "Data Source=localhost;Initial Catalog=AzureRedisCacheApi;Integrated Security=True;MultipleActiveResultSets=True;TrustServerCertificate=True;"
10+
"Default": "Data Source=localhost;Initial Catalog=AzureRedisCacheApi;Integrated Security=True;MultipleActiveResultSets=True;TrustServerCertificate=True;",
11+
"AzureRedisUrl": "<YOUR-URL-HERE>:6380,password=<YOUR-PASSWORD-HERE>,ssl=True,abortConnect=False"
1112
}
1213
}

0 commit comments

Comments
 (0)