ASP.NET Core Web API

Output Caching & Response Caching

1 Views Updated 5/4/2026

Output Caching & Response Caching

The fastest database query is the one you never make. If an API endpoint returns data that rarely changes (like a list of Countries or an e-commerce Product Catalog), querying SQL every time 10,000 users load the homepage is an extreme waste of server resources. We fix this using Caching.

1. Response Caching (The Old Way)

Response Caching uses the [ResponseCache] attribute to instruct the Client's Browser or intermediary proxies (like Cloudflare) to store the data locally. It is highly dependent on HTTP Headers (Cache-Control).

// Tells the browser: "Do not ask the server for this exact URL again for 60 seconds."
[HttpGet("catalog")]
[ResponseCache(Duration = 60)]
public IActionResult GetCatalog() 
{
    var data = _db.Catalogs.ToList();
    return Ok(data);
}
Major Flaw: Response Caching is entirely Client-Side. If a user bypasses it (e.g., sending an Authorization header or an intricate query string), the server is still hit.

2. Output Caching (.NET 7+ The Modern Standard)

Output Caching intercepts the HTTP Response on the Server-Side. The first user to hit the endpoint pays the database penalty. The server then caches the exact JSON string in RAM. For the next 60 seconds, if anyone else hits that endpoint, ASP.NET Core instantly returns the cached JSON string, bypassing the Controller and the Database completely.

Step 1: Configuration in Program.cs

var builder = WebApplication.CreateBuilder(args);

// Add the memory caching service
builder.Services.AddOutputCache(); 
builder.Services.AddControllers();

var app = builder.Build();

// Activate middleware (MUST be placed before MapControllers!)
app.UseOutputCache(); 
app.MapControllers();

Step 2: Securing Endpoints

// The server holds this exact JSON string in RAM for 120 seconds.
[HttpGet("countries")]
[OutputCache(Duration = 120)]
public IActionResult GetCountries() 
{
    // First user triggers this. Next 10,000 users never even execute this method.
    var countries = _db.Countries.ToList();
    return Ok(countries);
}

3. Advanced Features: Cache Tagging & Eviction

What if the data changes *before* the 120 seconds expire? We don't want to serve stale data. We can dynamically evict the cache using Tagging.

// The Get endpoint tags the cached data with the label "product_list"
[HttpGet]
[OutputCache(PolicyName = "BaseCache", Tags = new[] { "product_list" })]
public IActionResult GetProducts() { ... }

// The POST endpoint creates a new product.
// Using DI, we inject IOutputCacheStore to instantly delete the old cache!
[HttpPost]
public async Task<IActionResult> CreateProduct(ProductDto dto, IOutputCacheStore cache)
{
    _db.Products.Add(dto);
    await _db.SaveChangesAsync();

    // VIOLENCE! Instantly evicts any cache tagged with "product_list".
    // The very next GET request will be forced to hit the database to get fresh data.
    await cache.EvictByTagAsync("product_list", default); 

    return Ok();
}

4. Interview Mastery

Q: "Why does Output Caching automatically disable itself if the client sends an 'Authorization: Bearer' token header, and how do we override it?"

Architect Answer: "Security. By default, ASP.NET Core refuses to cache Authenticated responses. Imagine if User A requests their private bank statement, and the server caches that JSON. If User B hits the exact same URL a second later, the server might accidentally serve User A's private banking data to User B! To cache authenticated data safely, you must create a custom OutputCache policy that VaryBy(userid) or specifically override the default policy. However, as an architect, I strongly recommend NEVER caching private user-specific JSON data via OutputCaching at the network level; rely on an explicit Redis Distributed Cache instead using `IDistributedCache`."

ASP.NET Core Web API
1. Fundamentals & HTTP
Introduction to ASP.NET Core Web API REST Principles and HTTP Methods Controllers & ControllerBase Routing (Attribute vs Conventional) Action Return Types (IActionResult)
2. Request Handling
Model Binding (FromQuery, FromBody, FromRoute) Dependency Injection (DI) Deep Dive App Settings & The Options Pattern
3. Data Access & Architecture
EF Core Setup in Web API DbContext & Migrations Repository & Unit of Work Pattern Asynchronous Programming (async/await)
4. Data Transfer & Validation
Data Transfer Objects (DTOs) & AutoMapper Model Validation (DataAnnotations) FluentValidation Integration
5. Advanced Concepts
Global Exception Handling Middleware Content Negotiation (JSON vs XML) Pagination & Filtering Advanced Searching & Sorting HATEOAS (Hypermedia) Implementation Output Caching & Response Caching
6. Security & Authorization
Cross-Origin Resource Sharing (CORS) JWT Authentication Setup Access Tokens & Refresh Tokens Workflow Role-Based & Policy-Based Authorization API Key Authentication Rate Limiting & Throttling
7. Documentation & Testing
Swagger & OpenAPI Configuration Customizing API Documentation Unit Testing Controllers (xUnit & Moq) Integration Testing (WebApplicationFactory)
8. Microservices & Deployment
Consuming External APIs (IHttpClientFactory) Health Checks & Diagnostics API Versioning Strategies Deploying APIs (Docker & Azure)