Skip to content

codingdroplets/dotnet-response-caching

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

3 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Response Caching in ASP.NET Core (.NET 10)

Server-side, client-side, and proxy caching in one beginner-friendly sample β€” 7 practical Minimal API endpoints covering every caching scenario with Swagger/OpenAPI.

.NET ASP.NET Core License: MIT Visit CodingDroplets YouTube Patreon Buy Me a Coffee GitHub


πŸš€ Support the Channel β€” Join on Patreon

If this sample saved you time, consider joining our Patreon community. You'll get exclusive .NET tutorials, premium code samples, and early access to new content β€” all for the price of a coffee.

πŸ‘‰ Join CodingDroplets on Patreon

Prefer a one-time tip? Buy us a coffee β˜•


🎯 What You'll Learn

  • How to configure Response Caching Middleware in ASP.NET Core
  • How to cache responses on the server, client, and proxy with Cache-Control
  • How to use Vary by query key for query-parameter-dependent caching
  • How to use Vary by header for header-based cache variations
  • How to disable caching for sensitive or dynamic endpoints
  • How to inspect cache behaviour using Cache-Control, Vary, and Age response headers

πŸ—ΊοΈ Architecture Overview

Client Request
      β”‚
      β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     Client Request                          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚
                      β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              Response Caching Middleware                    β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚  Cached response exists?                            β”‚   β”‚
β”‚  β”‚  YES β†’ return cached response (Age header added)    β”‚   β”‚
β”‚  β”‚  NO  β†’ forward to endpoint β†’ cache the response     β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚
                      β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   Minimal API Endpoints                     β”‚
β”‚  Products / User Profile / Time / Random / Private / Login  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚
                      β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              HTTP Response + Cache Headers                  β”‚
β”‚         Cache-Control Β· Vary Β· Age Β· ETag                   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“‹ Endpoints & Caching Strategies

Endpoint Method Cache Strategy Duration
/api/products GET Server + public 60 seconds
/api/products/by-category GET Vary by category query 120 seconds
/api/user-profile GET Client-only 300 seconds
/api/time GET Vary by Accept-Language header 10 seconds
/api/random-number GET No cache (no-store) β€”
/api/private-data GET No cache (private) β€”
/api/login POST No cache (security) β€”
/api/cache-status GET No cache (diagnostic) β€”

πŸ“ Project Structure

dotnet-response-caching/
β”œβ”€β”€ DotNetResponseCaching.sln
└── src/
    └── DotNetResponseCaching.Api/
        β”œβ”€β”€ Program.cs           # Middleware setup, endpoints, cache profiles
        β”œβ”€β”€ appsettings.json
        └── Properties/
            └── launchSettings.json

πŸ› οΈ Prerequisites

  • .NET 10 SDK
  • Any IDE: Visual Studio 2022+, VS Code, or JetBrains Rider

⚑ Quick Start

# Clone the repo
git clone https://github.com/codingdroplets/dotnet-response-caching.git
cd dotnet-response-caching

# Run the API
dotnet run --project src/DotNetResponseCaching.Api

# Open Swagger UI β†’ http://localhost:5000/swagger

πŸ”§ How It Works

Step 1 β€” Register Middleware and Cache Profiles

builder.Services.AddResponseCaching();

builder.Services.AddControllers(options =>
{
    options.CacheProfiles.Add("Default",
        new CacheProfile { Duration = 60 });       // 60s, any location
    options.CacheProfiles.Add("Short",
        new CacheProfile { Duration = 30, Location = ResponseCacheLocation.Client });
    options.CacheProfiles.Add("Long",
        new CacheProfile { Duration = 300, VaryByQueryKeys = new[] { "category", "page" } });
});

// Must be placed before routing middleware
app.UseResponseCaching();

Step 2 β€” Decorate Endpoints with Cache Behaviour

// Server-side cache for 60 seconds
app.MapGet("/api/products", GetProducts)
   .CacheOutput(p => p.Expire(TimeSpan.FromSeconds(60)));

// Vary by query key β€” each category cached separately
app.MapGet("/api/products/by-category", GetByCategory)
   .CacheOutput(p => p.Expire(TimeSpan.FromSeconds(120)).SetVaryByQuery("category"));

// Client-only β€” no server-side store
app.MapGet("/api/user-profile", GetUserProfile)
   .CacheOutput(p => p.Expire(TimeSpan.FromSeconds(300)).NoStore());

// No caching for sensitive/dynamic endpoints
app.MapPost("/api/login", Login)
   .CacheOutput(p => p.NoStore());

Step 3 β€” Read the Cache Headers

Make a request, then check response headers:

curl -I http://localhost:5000/api/products
# Cache-Control: public, max-age=60
# Age: 0   ← first hit (not yet cached)

curl -I http://localhost:5000/api/products
# Age: 4   ← served from cache

πŸ€” Cache Headers Explained

Header Description
Cache-Control Directives: public, private, no-store, max-age
Vary Which request headers affect cache key (Accept-Language, etc.)
Age Seconds this response has been in cache
ETag Identifier for a specific version of the content

πŸ€” Response Caching vs Related Concepts

Type What It Caches Storage Use When
Response Caching HTTP responses (this sample) Server memory / proxy Public, rarely-changing API responses
Output Caching Entire rendered output In-memory (server) Razor Pages, full page caching
In-Memory Caching Arbitrary objects (IMemoryCache) Server memory Internal data, computed results
Distributed Caching Arbitrary objects (Redis / SQL) External store Multi-server / load-balanced apps

πŸ“š References


πŸ“„ License

This project is licensed under the MIT License.


πŸ”— Connect with CodingDroplets

Platform Link
🌐 Website https://codingdroplets.com/
πŸ“Ί YouTube https://www.youtube.com/@CodingDroplets
🎁 Patreon https://www.patreon.com/CodingDroplets
β˜• Buy Me a Coffee https://buymeacoffee.com/codingdroplets
πŸ’» GitHub http://github.com/codingdroplets/

Want more samples like this? Support us on Patreon or buy us a coffee β˜• β€” every bit helps keep the content coming!

About

ASP.NET Core Minimal API sample demonstrating Response Caching Middleware with Swagger and beginner-friendly structure.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages