├── .gitignore ├── README.md ├── lesson_1 └── interacting_with_redis.linq ├── lesson_2 ├── AspNetCoreRedis │ ├── AspNetCoreRedis.sln │ └── AspNetCoreRedis │ │ ├── AspNetCoreRedis.csproj │ │ ├── Controllers │ │ └── HomeController.cs │ │ ├── Program.cs │ │ ├── Properties │ │ └── launchSettings.json │ │ ├── Startup.cs │ │ ├── appsettings.Development.json │ │ └── appsettings.json └── interacting_with_redis_clients.linq ├── lesson_3 ├── CachingStrategies │ ├── CachingStrategies.sln │ └── CachingStrategies │ │ ├── 0_MemoryCache.cs │ │ ├── 0_RedisCache.cs │ │ ├── 1_NamespacedCache.cs │ │ ├── 2_FallBackCache.cs │ │ ├── 3_WriteThroughCache.cs │ │ ├── 4_WriteBackCache.cs │ │ ├── CachingStrategies.csproj │ │ └── Extensions.cs ├── aside_read.png ├── lazy_read.png ├── write_aside.png ├── write_back.png └── write_through.png ├── lesson_4 └── WebApp │ ├── Dockerfile │ ├── WebApp.sln │ └── WebApp │ ├── DefaultController.cs │ ├── IDistributedCacheExtensions.cs │ ├── Program.cs │ ├── Properties │ └── launchSettings.json │ ├── ServiceOne.cs │ ├── ServiceThree.cs │ ├── ServiceTwo.cs │ ├── Startup.cs │ ├── WebApp.csproj │ ├── appsettings.Development.json │ └── appsettings.json └── lesson_6 ├── distributed_cache_ttl.linq └── redis_lru_policy_check.linq /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | bin 3 | obj -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Redis Distributed Caching with ASPNET Core & Redis 2 | 3 | [Full Youtube playlist](https://youtube.com/playlist?list=PLOeFnOV9YBa77eJeW39a5Q2lsyfdxpE_d) 4 | 5 | ## Episodes 6 | 1. [Introduction & Setup](https://youtu.be/fb0XZTAURCo) 7 | 2. [StackExchange.Redis & IDistributedCaching](https://youtu.be/rsXvpCHdldg) 8 | 3. [Caching Strategies & Theory](https://youtu.be/EJ73Bl3AtFY) 9 | 4. [Project Setup & Practice](https://youtu.be/eNEAdd8J-WY) 10 | 5. [Running in the Cloud](https://youtu.be/-heHQR1Jmuk) 11 | 6. [Configuration and Final Thoughts](https://youtu.be/u05Y_H1rE-c) 12 | -------------------------------------------------------------------------------- /lesson_1/interacting_with_redis.linq: -------------------------------------------------------------------------------- 1 | 2 | System.Net.Sockets 3 | 4 | 5 | void Main() 6 | { 7 | var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 8 | 9 | socket.Connect("127.0.0.1", 6379); 10 | 11 | var responseStream = new BufferedStream(new NetworkStream(socket), 1024); 12 | 13 | var requestString = "*2\r\n$3\r\nGET\r\n$3\r\ncat\r\n"; 14 | byte[] request = Encoding.UTF8.GetBytes(requestString); 15 | socket.Send(request); 16 | 17 | 18 | var result = new StringBuilder(); 19 | int b; 20 | 21 | while((b = responseStream.ReadByte()) != -1){ 22 | if(b == '\r'){ 23 | responseStream.ReadByte(); 24 | break; 25 | } 26 | result.Append((char) b); 27 | } 28 | 29 | var responseLength = int.Parse(result.ToString().Substring(1)); 30 | var responseValue = new byte[responseLength]; 31 | responseStream.Read(responseValue, 0, responseLength); 32 | Encoding.UTF8.GetString(responseValue).Dump("result"); 33 | } -------------------------------------------------------------------------------- /lesson_2/AspNetCoreRedis/AspNetCoreRedis.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspNetCoreRedis", "AspNetCoreRedis\AspNetCoreRedis.csproj", "{CFA58D2B-163F-4BC2-9382-625254C8982A}" 4 | EndProject 5 | Global 6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 7 | Debug|Any CPU = Debug|Any CPU 8 | Release|Any CPU = Release|Any CPU 9 | EndGlobalSection 10 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 11 | {CFA58D2B-163F-4BC2-9382-625254C8982A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 12 | {CFA58D2B-163F-4BC2-9382-625254C8982A}.Debug|Any CPU.Build.0 = Debug|Any CPU 13 | {CFA58D2B-163F-4BC2-9382-625254C8982A}.Release|Any CPU.ActiveCfg = Release|Any CPU 14 | {CFA58D2B-163F-4BC2-9382-625254C8982A}.Release|Any CPU.Build.0 = Release|Any CPU 15 | EndGlobalSection 16 | EndGlobal 17 | -------------------------------------------------------------------------------- /lesson_2/AspNetCoreRedis/AspNetCoreRedis/AspNetCoreRedis.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /lesson_2/AspNetCoreRedis/AspNetCoreRedis/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Mvc; 3 | using Microsoft.Extensions.Caching.Distributed; 4 | 5 | namespace AspNetCoreRedis.Controllers 6 | { 7 | public class HomeController : ControllerBase 8 | { 9 | public IActionResult Index([FromServices] IDistributedCache cache) 10 | { 11 | return Ok(cache.GetString("rat")); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /lesson_2/AspNetCoreRedis/AspNetCoreRedis/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Hosting; 6 | using Microsoft.Extensions.Configuration; 7 | using Microsoft.Extensions.Hosting; 8 | using Microsoft.Extensions.Logging; 9 | 10 | namespace AspNetCoreRedis 11 | { 12 | public class Program 13 | { 14 | public static void Main(string[] args) 15 | { 16 | CreateHostBuilder(args).Build().Run(); 17 | } 18 | 19 | public static IHostBuilder CreateHostBuilder(string[] args) => 20 | Host.CreateDefaultBuilder(args) 21 | .ConfigureWebHostDefaults(webBuilder => 22 | { 23 | webBuilder.UseStartup(); 24 | }); 25 | } 26 | } -------------------------------------------------------------------------------- /lesson_2/AspNetCoreRedis/AspNetCoreRedis/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:6734", 7 | "sslPort": 44308 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "AspNetCoreRedis": { 19 | "commandName": "Project", 20 | "dotnetRunMessages": "true", 21 | "launchBrowser": true, 22 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 23 | "environmentVariables": { 24 | "ASPNETCORE_ENVIRONMENT": "Development" 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lesson_2/AspNetCoreRedis/AspNetCoreRedis/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Builder; 6 | using Microsoft.AspNetCore.Hosting; 7 | using Microsoft.AspNetCore.Http; 8 | using Microsoft.Extensions.DependencyInjection; 9 | using Microsoft.Extensions.Hosting; 10 | 11 | namespace AspNetCoreRedis 12 | { 13 | public class Startup 14 | { 15 | // This method gets called by the runtime. Use this method to add services to the container. 16 | // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 17 | public void ConfigureServices(IServiceCollection services) 18 | { 19 | services.AddControllers(); 20 | 21 | services.AddStackExchangeRedisCache(config => 22 | { 23 | config.Configuration = "127.0.0.1:6379"; 24 | }); 25 | } 26 | 27 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 28 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 29 | { 30 | if (env.IsDevelopment()) 31 | { 32 | app.UseDeveloperExceptionPage(); 33 | } 34 | 35 | app.UseRouting(); 36 | 37 | app.UseEndpoints(endpoints => 38 | { 39 | endpoints.MapDefaultControllerRoute(); 40 | }); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /lesson_2/AspNetCoreRedis/AspNetCoreRedis/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /lesson_2/AspNetCoreRedis/AspNetCoreRedis/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*" 10 | } 11 | -------------------------------------------------------------------------------- /lesson_2/interacting_with_redis_clients.linq: -------------------------------------------------------------------------------- 1 | 2 | Microsoft.Extensions.Caching.StackExchangeRedis 3 | StackExchange.Redis 4 | StackExchange.Redis 5 | Microsoft.Extensions.Caching.StackExchangeRedis 6 | Microsoft.Extensions.Options 7 | Microsoft.Extensions.Caching.Distributed 8 | 9 | 10 | void Main() 11 | { 12 | //ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("127.0.0.1"); 13 | // 14 | //IDatabase db = redis.GetDatabase(); 15 | // 16 | //db.StringGet("dog").Dump(); 17 | //db.StringGet("cat").Dump(); 18 | 19 | 20 | var options = Options.Create(new RedisCacheOptions() 21 | { 22 | Configuration = "127.0.0.1:6379" 23 | }); 24 | IDistributedCache cache = new RedisCache(options); 25 | 26 | //cache.SetString("rat", "bob"); 27 | cache.GetString("rat").Dump(); 28 | 29 | } 30 | 31 | -------------------------------------------------------------------------------- /lesson_3/CachingStrategies/CachingStrategies.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CachingStrategies", "CachingStrategies\CachingStrategies.csproj", "{36A4E26C-46B7-49DE-B6E9-120616F9CB7E}" 4 | EndProject 5 | Global 6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 7 | Debug|Any CPU = Debug|Any CPU 8 | Release|Any CPU = Release|Any CPU 9 | EndGlobalSection 10 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 11 | {36A4E26C-46B7-49DE-B6E9-120616F9CB7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 12 | {36A4E26C-46B7-49DE-B6E9-120616F9CB7E}.Debug|Any CPU.Build.0 = Debug|Any CPU 13 | {36A4E26C-46B7-49DE-B6E9-120616F9CB7E}.Release|Any CPU.ActiveCfg = Release|Any CPU 14 | {36A4E26C-46B7-49DE-B6E9-120616F9CB7E}.Release|Any CPU.Build.0 = Release|Any CPU 15 | EndGlobalSection 16 | EndGlobal 17 | -------------------------------------------------------------------------------- /lesson_3/CachingStrategies/CachingStrategies/0_MemoryCache.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using Microsoft.Extensions.Caching.Distributed; 5 | 6 | namespace CachingStrategies 7 | { 8 | public class MemoryCache : IDistributedCache 9 | { 10 | public byte[] Get(string key) 11 | { 12 | throw new System.NotImplementedException(); 13 | } 14 | 15 | public Task GetAsync(string key, CancellationToken token = new CancellationToken()) 16 | { 17 | throw new System.NotImplementedException(); 18 | } 19 | 20 | public void Set(string key, byte[] value, DistributedCacheEntryOptions options) 21 | { 22 | throw new System.NotImplementedException(); 23 | } 24 | 25 | public Task SetAsync(string key, byte[] value, DistributedCacheEntryOptions options, CancellationToken token = new CancellationToken()) 26 | { 27 | throw new System.NotImplementedException(); 28 | } 29 | 30 | public void Refresh(string key) 31 | { 32 | throw new System.NotImplementedException(); 33 | } 34 | 35 | public Task RefreshAsync(string key, CancellationToken token = new CancellationToken()) 36 | { 37 | throw new System.NotImplementedException(); 38 | } 39 | 40 | public void Remove(string key) 41 | { 42 | throw new System.NotImplementedException(); 43 | } 44 | 45 | public Task RemoveAsync(string key, CancellationToken token = new CancellationToken()) 46 | { 47 | throw new System.NotImplementedException(); 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /lesson_3/CachingStrategies/CachingStrategies/0_RedisCache.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using Microsoft.Extensions.Caching.Distributed; 4 | 5 | namespace CachingStrategies 6 | { 7 | public class RedisCache : IDistributedCache 8 | { 9 | public byte[] Get(string key) 10 | { 11 | throw new System.NotImplementedException(); 12 | } 13 | 14 | public Task GetAsync(string key, CancellationToken token = new CancellationToken()) 15 | { 16 | throw new System.NotImplementedException(); 17 | } 18 | 19 | public void Set(string key, byte[] value, DistributedCacheEntryOptions options) 20 | { 21 | throw new System.NotImplementedException(); 22 | } 23 | 24 | public Task SetAsync(string key, byte[] value, DistributedCacheEntryOptions options, CancellationToken token = new CancellationToken()) 25 | { 26 | throw new System.NotImplementedException(); 27 | } 28 | 29 | public void Refresh(string key) 30 | { 31 | throw new System.NotImplementedException(); 32 | } 33 | 34 | public Task RefreshAsync(string key, CancellationToken token = new CancellationToken()) 35 | { 36 | throw new System.NotImplementedException(); 37 | } 38 | 39 | public void Remove(string key) 40 | { 41 | throw new System.NotImplementedException(); 42 | } 43 | 44 | public Task RemoveAsync(string key, CancellationToken token = new CancellationToken()) 45 | { 46 | throw new System.NotImplementedException(); 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /lesson_3/CachingStrategies/CachingStrategies/1_NamespacedCache.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using Microsoft.Extensions.Caching.Distributed; 4 | 5 | namespace CachingStrategies 6 | { 7 | public class NamespacedCache : IDistributedCache 8 | { 9 | private readonly IDistributedCache _cache; 10 | private readonly string _name; 11 | 12 | public NamespacedCache(IDistributedCache cache, string name) 13 | { 14 | _cache = cache.ToNamespaced("products"); 15 | _name = name; 16 | } 17 | 18 | public byte[] Get(string key) => _cache.Get(_name + key); 19 | 20 | public Task GetAsync(string key, CancellationToken token = new CancellationToken()) 21 | { 22 | throw new System.NotImplementedException(); 23 | } 24 | 25 | public void Set(string key, byte[] value, DistributedCacheEntryOptions options) 26 | { 27 | throw new System.NotImplementedException(); 28 | } 29 | 30 | public Task SetAsync(string key, byte[] value, DistributedCacheEntryOptions options, CancellationToken token = new CancellationToken()) 31 | { 32 | throw new System.NotImplementedException(); 33 | } 34 | 35 | public void Refresh(string key) 36 | { 37 | throw new System.NotImplementedException(); 38 | } 39 | 40 | public Task RefreshAsync(string key, CancellationToken token = new CancellationToken()) 41 | { 42 | throw new System.NotImplementedException(); 43 | } 44 | 45 | public void Remove(string key) 46 | { 47 | throw new System.NotImplementedException(); 48 | } 49 | 50 | public Task RemoveAsync(string key, CancellationToken token = new CancellationToken()) 51 | { 52 | throw new System.NotImplementedException(); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /lesson_3/CachingStrategies/CachingStrategies/2_FallBackCache.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using Microsoft.Extensions.Caching.Distributed; 5 | 6 | namespace CachingStrategies 7 | { 8 | public class FallBackCache : IDistributedCache 9 | { 10 | private readonly IDistributedCache _main; 11 | private readonly IDistributedCache _secondary; 12 | 13 | private int failCount; 14 | 15 | public FallBackCache(IDistributedCache main, IDistributedCache secondary) 16 | { 17 | _main = main; 18 | _secondary = secondary; 19 | } 20 | 21 | public byte[] Get(string key) 22 | { 23 | try 24 | { 25 | if (failCount < 3) 26 | _main.Get(key); 27 | } 28 | catch (Exception e) 29 | { 30 | failCount++; 31 | } 32 | 33 | return _secondary.Get(key); 34 | } 35 | 36 | public Task GetAsync(string key, CancellationToken token = new CancellationToken()) 37 | { 38 | throw new System.NotImplementedException(); 39 | } 40 | 41 | public void Set(string key, byte[] value, DistributedCacheEntryOptions options) 42 | { 43 | throw new System.NotImplementedException(); 44 | } 45 | 46 | public Task SetAsync(string key, byte[] value, DistributedCacheEntryOptions options, CancellationToken token = new CancellationToken()) 47 | { 48 | throw new System.NotImplementedException(); 49 | } 50 | 51 | public void Refresh(string key) 52 | { 53 | throw new System.NotImplementedException(); 54 | } 55 | 56 | public Task RefreshAsync(string key, CancellationToken token = new CancellationToken()) 57 | { 58 | throw new System.NotImplementedException(); 59 | } 60 | 61 | public void Remove(string key) 62 | { 63 | throw new System.NotImplementedException(); 64 | } 65 | 66 | public Task RemoveAsync(string key, CancellationToken token = new CancellationToken()) 67 | { 68 | throw new System.NotImplementedException(); 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /lesson_3/CachingStrategies/CachingStrategies/3_WriteThroughCache.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using Microsoft.Extensions.Caching.Distributed; 4 | 5 | namespace CachingStrategies 6 | { 7 | public class WriteThroughCache : IDistributedCache 8 | { 9 | private readonly IDistributedCache _main; 10 | private readonly IDistributedCache _secondary; 11 | 12 | public WriteThroughCache(IDistributedCache main, IDistributedCache secondary) 13 | { 14 | _main = main; 15 | _secondary = secondary; 16 | } 17 | 18 | // read aside 19 | public byte[] Get(string key) 20 | { 21 | var value = _secondary.Get(key); 22 | if (value == null) 23 | { 24 | value = _main.Get(key); 25 | _secondary.Set(key, value); 26 | } 27 | 28 | return value; 29 | } 30 | 31 | public Task GetAsync(string key, CancellationToken token = new CancellationToken()) 32 | { 33 | throw new System.NotImplementedException(); 34 | } 35 | 36 | public void Set(string key, byte[] value, DistributedCacheEntryOptions options) 37 | { 38 | _secondary.Set(key, value); 39 | _main.Set(key, value); 40 | } 41 | 42 | public Task SetAsync(string key, byte[] value, DistributedCacheEntryOptions options, CancellationToken token = new CancellationToken()) 43 | { 44 | throw new System.NotImplementedException(); 45 | } 46 | 47 | public void Refresh(string key) 48 | { 49 | throw new System.NotImplementedException(); 50 | } 51 | 52 | public Task RefreshAsync(string key, CancellationToken token = new CancellationToken()) 53 | { 54 | throw new System.NotImplementedException(); 55 | } 56 | 57 | public void Remove(string key) 58 | { 59 | throw new System.NotImplementedException(); 60 | } 61 | 62 | public Task RemoveAsync(string key, CancellationToken token = new CancellationToken()) 63 | { 64 | throw new System.NotImplementedException(); 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /lesson_3/CachingStrategies/CachingStrategies/4_WriteBackCache.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using Microsoft.Extensions.Caching.Distributed; 6 | 7 | namespace CachingStrategies 8 | { 9 | public class WriteBackCache : IDistributedCache 10 | { 11 | private readonly IDistributedCache _main; 12 | private readonly IDistributedCache _secondary; 13 | 14 | public WriteBackCache(IDistributedCache main, IDistributedCache secondary) 15 | { 16 | _main = main; 17 | _secondary = secondary; 18 | _backgroundTask = Task.Run(WriteBack); 19 | } 20 | 21 | public byte[] Get(string key) 22 | { 23 | throw new System.NotImplementedException(); 24 | } 25 | 26 | public Task GetAsync(string key, CancellationToken token = new CancellationToken()) 27 | { 28 | throw new System.NotImplementedException(); 29 | } 30 | 31 | private List> writeBackBuffer = new(); 32 | private readonly Task _backgroundTask; 33 | 34 | private async Task WriteBack() 35 | { 36 | while (true) 37 | { 38 | try 39 | { 40 | if (writeBackBuffer.Count > 100) 41 | { 42 | // build batch update 43 | } 44 | 45 | await Task.Delay(1000 * 60); 46 | } 47 | catch (Exception e) 48 | { 49 | 50 | } 51 | } 52 | } 53 | 54 | public void Set(string key, byte[] value, DistributedCacheEntryOptions options) 55 | { 56 | _secondary.Set(key, value); 57 | writeBackBuffer.Add(KeyValuePair.Create(key, value)); 58 | } 59 | 60 | public Task SetAsync(string key, byte[] value, DistributedCacheEntryOptions options, CancellationToken token = new CancellationToken()) 61 | { 62 | throw new System.NotImplementedException(); 63 | } 64 | 65 | public void Refresh(string key) 66 | { 67 | throw new System.NotImplementedException(); 68 | } 69 | 70 | public Task RefreshAsync(string key, CancellationToken token = new CancellationToken()) 71 | { 72 | throw new System.NotImplementedException(); 73 | } 74 | 75 | public void Remove(string key) 76 | { 77 | throw new System.NotImplementedException(); 78 | } 79 | 80 | public Task RemoveAsync(string key, CancellationToken token = new CancellationToken()) 81 | { 82 | throw new System.NotImplementedException(); 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /lesson_3/CachingStrategies/CachingStrategies/CachingStrategies.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /lesson_3/CachingStrategies/CachingStrategies/Extensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Caching.Distributed; 2 | 3 | namespace CachingStrategies 4 | { 5 | public static class Extensions 6 | { 7 | public static IDistributedCache ToNamespaced(this IDistributedCache @this, string name) => 8 | new NamespacedCache(@this, name); 9 | } 10 | } -------------------------------------------------------------------------------- /lesson_3/aside_read.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raw-coding-youtube/aspnetcore-redis-distributed-caching/7a8f5e6dc527e172c9eba2c51fcb501a0dc04dba/lesson_3/aside_read.png -------------------------------------------------------------------------------- /lesson_3/lazy_read.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raw-coding-youtube/aspnetcore-redis-distributed-caching/7a8f5e6dc527e172c9eba2c51fcb501a0dc04dba/lesson_3/lazy_read.png -------------------------------------------------------------------------------- /lesson_3/write_aside.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raw-coding-youtube/aspnetcore-redis-distributed-caching/7a8f5e6dc527e172c9eba2c51fcb501a0dc04dba/lesson_3/write_aside.png -------------------------------------------------------------------------------- /lesson_3/write_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raw-coding-youtube/aspnetcore-redis-distributed-caching/7a8f5e6dc527e172c9eba2c51fcb501a0dc04dba/lesson_3/write_back.png -------------------------------------------------------------------------------- /lesson_3/write_through.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raw-coding-youtube/aspnetcore-redis-distributed-caching/7a8f5e6dc527e172c9eba2c51fcb501a0dc04dba/lesson_3/write_through.png -------------------------------------------------------------------------------- /lesson_4/WebApp/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/aspnet:5.0 2 | 3 | WORKDIR /app 4 | 5 | COPY WebApp/bin/Release/net5.0/publish . 6 | 7 | EXPOSE 5000 8 | 9 | CMD ["dotnet", "WebApp.dll"] -------------------------------------------------------------------------------- /lesson_4/WebApp/WebApp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApp", "WebApp\WebApp.csproj", "{9472701A-3B77-461D-B005-B1C1A9008BE4}" 4 | EndProject 5 | Global 6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 7 | Debug|Any CPU = Debug|Any CPU 8 | Release|Any CPU = Release|Any CPU 9 | EndGlobalSection 10 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 11 | {9472701A-3B77-461D-B005-B1C1A9008BE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 12 | {9472701A-3B77-461D-B005-B1C1A9008BE4}.Debug|Any CPU.Build.0 = Debug|Any CPU 13 | {9472701A-3B77-461D-B005-B1C1A9008BE4}.Release|Any CPU.ActiveCfg = Release|Any CPU 14 | {9472701A-3B77-461D-B005-B1C1A9008BE4}.Release|Any CPU.Build.0 = Release|Any CPU 15 | EndGlobalSection 16 | EndGlobal 17 | -------------------------------------------------------------------------------- /lesson_4/WebApp/WebApp/DefaultController.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | using System.Threading.Tasks; 3 | using Microsoft.AspNetCore.Http; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.Extensions.Caching.Distributed; 6 | 7 | namespace WebApp 8 | { 9 | public class DefaultController : ControllerBase 10 | { 11 | private readonly IDistributedCache _cache; 12 | 13 | public DefaultController(IDistributedCache cache) 14 | { 15 | _cache = cache; 16 | } 17 | 18 | [HttpGet("/one")] 19 | public async Task One([FromServices] ServiceOne one, [FromQuery] int n = 1) 20 | { 21 | var res = await _cache.GetOrAddAsync(n, one.GetCarAsync); 22 | 23 | return Ok(res); 24 | } 25 | 26 | [HttpGet("/two")] 27 | public async Task Two([FromServices] ServiceTwo two, [FromQuery] string key = "foo") 28 | { 29 | var res = await _cache.GetOrAddAsync(key, two.GetNameAsync); 30 | 31 | return Ok(res); 32 | } 33 | 34 | [HttpGet("/three")] 35 | public async Task Three([FromServices] ServiceThree three) 36 | { 37 | Dude dude = new(1, "Bob"); 38 | await _cache.SetAsync(dude); 39 | await three.SaveDudeAsync(dude); 40 | return Ok(); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /lesson_4/WebApp/WebApp/IDistributedCacheExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.Json; 3 | using System.Threading.Tasks; 4 | using Microsoft.Extensions.Caching.Distributed; 5 | 6 | namespace WebApp 7 | { 8 | public static class IDistributedCacheExtensions 9 | { 10 | public static async Task> GetOrAddAsync( 11 | this IDistributedCache cache, 12 | TKey anyKey, 13 | Func> factory 14 | ) 15 | where T : class 16 | { 17 | var key = anyKey switch 18 | { 19 | string k => k, 20 | _ => anyKey.ToString(), 21 | }; 22 | 23 | var value = await cache.GetAsync(key); 24 | if (value == null) 25 | { 26 | value = await factory(anyKey); 27 | await cache.SetStringAsync(key, JsonSerializer.Serialize(value)); 28 | return new(false, value); 29 | } 30 | 31 | return new(true, value); 32 | } 33 | 34 | public static async Task GetAsync(this IDistributedCache cache, string key) 35 | where T : class 36 | { 37 | var jsonValue = await cache.GetStringAsync(key); 38 | if (string.IsNullOrEmpty(jsonValue)) 39 | { 40 | return null; 41 | } 42 | 43 | return JsonSerializer.Deserialize(jsonValue); 44 | } 45 | 46 | public static async Task GetLongAsync(this IDistributedCache cache, string key) 47 | { 48 | var value = await cache.GetAsync(key); 49 | return BitConverter.ToInt64(value); 50 | } 51 | 52 | public static Task SetLongAsync(this IDistributedCache cache, string key, long value) 53 | { 54 | return cache.SetAsync(key, BitConverter.GetBytes(value)); 55 | } 56 | 57 | public static async Task GetDateTimeAsync(this IDistributedCache cache, string key) 58 | { 59 | var value = await cache.GetAsync(key); 60 | var ticks = BitConverter.ToInt64(value); 61 | return new(ticks); 62 | } 63 | 64 | public static Task SetDateTimeAsync(this IDistributedCache cache, string key, DateTime value) 65 | { 66 | var ticks = value.Ticks; 67 | return cache.SetAsync(key, BitConverter.GetBytes(ticks)); 68 | } 69 | 70 | public static Task SetAsync(this IDistributedCache cache, T value) 71 | where T : ICacheKey 72 | { 73 | return cache.SetStringAsync(value.CacheKey, JsonSerializer.Serialize(value)); 74 | } 75 | 76 | public record GetCachedValue(bool Cached, T value); 77 | } 78 | } -------------------------------------------------------------------------------- /lesson_4/WebApp/WebApp/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.Extensions.Hosting; 3 | 4 | namespace WebApp 5 | { 6 | public class Program 7 | { 8 | public static void Main(string[] args) 9 | { 10 | CreateHostBuilder(args).Build().Run(); 11 | } 12 | 13 | public static IHostBuilder CreateHostBuilder(string[] args) => 14 | Host.CreateDefaultBuilder(args) 15 | .ConfigureWebHostDefaults(webBuilder => 16 | { 17 | webBuilder.UseStartup() 18 | .UseUrls("http://0.0.0.0:5000"); 19 | }); 20 | } 21 | } -------------------------------------------------------------------------------- /lesson_4/WebApp/WebApp/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:19848", 7 | "sslPort": 44328 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "WebApp": { 19 | "commandName": "Project", 20 | "dotnetRunMessages": "true", 21 | "launchBrowser": true, 22 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 23 | "environmentVariables": { 24 | "ASPNETCORE_ENVIRONMENT": "Development" 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lesson_4/WebApp/WebApp/ServiceOne.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace WebApp 4 | { 5 | public class ServiceOne 6 | { 7 | public async Task GetCarAsync(int id) 8 | { 9 | await Task.Delay(5000); 10 | return new(id, $"Volvo {id}", "Me"); 11 | } 12 | } 13 | 14 | public record Car(int Id, string Mark, string Owner); 15 | } -------------------------------------------------------------------------------- /lesson_4/WebApp/WebApp/ServiceThree.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace WebApp 4 | { 5 | public class ServiceThree 6 | { 7 | public Task SaveDudeAsync(Dude dude) => Task.CompletedTask; 8 | } 9 | 10 | public record Dude(int Id, string Name, bool Cool = true) : ICacheKey 11 | { 12 | public string CacheKey => $"dude_{Id}"; 13 | } 14 | 15 | public interface ICacheKey 16 | { 17 | string CacheKey { get; } 18 | } 19 | } -------------------------------------------------------------------------------- /lesson_4/WebApp/WebApp/ServiceTwo.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace WebApp 4 | { 5 | public class ServiceTwo 6 | { 7 | public Task GetNameAsync(string id) => Task.FromResult("Bob"); 8 | } 9 | } -------------------------------------------------------------------------------- /lesson_4/WebApp/WebApp/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Builder; 3 | using Microsoft.AspNetCore.Hosting; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Microsoft.Extensions.Hosting; 6 | 7 | namespace WebApp 8 | { 9 | public class Startup 10 | { 11 | private readonly IWebHostEnvironment _env; 12 | 13 | public Startup(IWebHostEnvironment env) => _env = env; 14 | 15 | public void ConfigureServices(IServiceCollection services) 16 | { 17 | services.AddControllers(); 18 | 19 | services.AddStackExchangeRedisCache(config => 20 | { 21 | config.Configuration = _env.IsDevelopment() 22 | ? "127.0.0.1:6379" 23 | : Environment.GetEnvironmentVariable("REDIS_URL"); 24 | } 25 | ); 26 | 27 | services.AddTransient() 28 | .AddTransient() 29 | .AddTransient(); 30 | } 31 | 32 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 33 | { 34 | if (env.IsDevelopment()) 35 | { 36 | app.UseDeveloperExceptionPage(); 37 | } 38 | 39 | app.UseRouting(); 40 | 41 | app.UseEndpoints(endpoints => 42 | { 43 | endpoints.MapDefaultControllerRoute(); 44 | }); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /lesson_4/WebApp/WebApp/WebApp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | 9.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /lesson_4/WebApp/WebApp/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /lesson_4/WebApp/WebApp/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*" 10 | } 11 | -------------------------------------------------------------------------------- /lesson_6/distributed_cache_ttl.linq: -------------------------------------------------------------------------------- 1 | 2 | Microsoft.Extensions.Caching.StackExchangeRedis 3 | StackExchange.Redis 4 | StackExchange.Redis 5 | Microsoft.Extensions.Caching.StackExchangeRedis 6 | Microsoft.Extensions.Options 7 | Microsoft.Extensions.Caching.Distributed 8 | System.Threading.Tasks 9 | 10 | 11 | IDistributedCache _cache = new RedisCache( 12 | Options.Create(new RedisCacheOptions() 13 | { 14 | Configuration = "127.0.0.1:6379" 15 | }) 16 | ); 17 | 18 | void Main() 19 | { 20 | //AbsoluteExpiration(); 21 | 22 | // SlidingExpiration(); 23 | 24 | _cache.GetString("key"); 25 | } 26 | 27 | public void AbsoluteExpiration() 28 | { 29 | var options = new DistributedCacheEntryOptions() 30 | { 31 | AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(20) 32 | }; 33 | 34 | _cache.SetString("key", "string", options); 35 | } 36 | 37 | public void SlidingExpiration() 38 | { 39 | var options = new DistributedCacheEntryOptions() 40 | { 41 | SlidingExpiration = TimeSpan.FromSeconds(30) 42 | }; 43 | 44 | _cache.SetString("key", "string", options); 45 | } -------------------------------------------------------------------------------- /lesson_6/redis_lru_policy_check.linq: -------------------------------------------------------------------------------- 1 | 2 | Microsoft.Extensions.Caching.StackExchangeRedis 3 | StackExchange.Redis 4 | StackExchange.Redis 5 | Microsoft.Extensions.Caching.StackExchangeRedis 6 | Microsoft.Extensions.Options 7 | Microsoft.Extensions.Caching.Distributed 8 | System.Threading.Tasks 9 | 10 | 11 | void Main() 12 | { 13 | IDistributedCache cache = new RedisCache( 14 | Options.Create(new RedisCacheOptions() 15 | { 16 | Configuration = "127.0.0.1:6379" 17 | }) 18 | ); 19 | 20 | var twoMegabytes = (1024 * 1024 * 2); 21 | var chunks = 10; 22 | var chunkSize = twoMegabytes / chunks; 23 | 24 | var bigWords = Enumerable.Range(0, chunks + 1).Select(_ => BigA(chunkSize)); 25 | 26 | int i = 0; 27 | foreach (var word in bigWords) 28 | { 29 | cache.SetString(i.ToString(), word); 30 | cache.Get(0.ToString()); 31 | i++; 32 | } 33 | } 34 | 35 | public string BigA(int length) 36 | { 37 | var builder = new StringBuilder(); 38 | 39 | for (int i = 0; i < length; i++) 40 | { 41 | builder.Append("a"); 42 | } 43 | 44 | return builder.ToString(); 45 | } --------------------------------------------------------------------------------