Minimize latency and database load across every layer of the request lifecycle — from the browser edge to SQL Server — using a coordinated multi-layer caching approach.
// Register Redis distributed cache in Program.cs builder.Services.AddStackExchangeRedisCache(options => { options.Configuration = "your-elasticache-endpoint:6379"; options.InstanceName = "MyApp:"; }); // Inject IDistributedCache in your service / controller public class ProductService(IDistributedCache cache, AppDbContext db) { public async Task<Product> GetByIdAsync(int id) { var key = $"product:{id}"; var json = await cache.GetStringAsync(key); if (json is not null) return JsonSerializer.Deserialize<Product>(json)!; var product = await db.Products.FindAsync(id); await cache.SetStringAsync(key, JsonSerializer.Serialize(product), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10) }); return product!; } }
// Cache this response for 60 seconds, vary by query string [HttpGet] [ResponseCache(Duration = 60, Location = ResponseCacheLocation.Any, VaryByQueryKeys = new[] { "category", "page" })] public async Task<IActionResult> GetProducts(string? category, int page = 1) { var products = await _service.GetProductsAsync(category, page); return Ok(products); }
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { shareReplay } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class DataService { private cache$: Observable<Product[]> | null = null; constructor(private http: HttpClient) {} getData(): Observable<Product[]> { if (!this.cache$) { this.cache$ = this.http.get<Product[]>('/api/products').pipe( shareReplay(1) // Caches the last emitted value for all subscribers ); } return this.cache$; } clearCache(): void { this.cache$ = null; } }
import { Injectable } from '@angular/core'; import { HttpInterceptor, HttpRequest, HttpHandler, HttpResponse } from '@angular/common/http'; import { of } from 'rxjs'; import { tap } from 'rxjs/operators'; @Injectable() export class CacheInterceptor implements HttpInterceptor { private cache = new Map<string, HttpResponse<unknown>>(); intercept(req: HttpRequest<unknown>, next: HttpHandler) { if (req.method !== 'GET') return next.handle(req); const cached = this.cache.get(req.url); if (cached) return of(cached.clone()); // ← cache hit return next.handle(req).pipe( tap(event => { if (event instanceof HttpResponse) this.cache.set(req.url, event); }) ); } }
/api/* requests to your EC2 or API Gateway origin. Apply a specific Cache Policy that varies by query string and Authorization header where needed.
/api/* → EC2 / API Gateway originenvironment.prod.ts with the EC2 instance's public DNS or your CloudFront distribution URL before running the build pipeline, so the production bundle points to the correct API endpoint.