惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园_首页
GbyAI
GbyAI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Apple Machine Learning Research
Apple Machine Learning Research
大猫的无限游戏
大猫的无限游戏
阮一峰的网络日志
阮一峰的网络日志
Last Week in AI
Last Week in AI
V
Visual Studio Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
The Cloudflare Blog
博客园 - 【当耐特】
博客园 - 叶小钗
量子位
博客园 - 聂微东
S
SegmentFault 最新的问题
美团技术团队
Hugging Face - Blog
Hugging Face - Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
月光博客
月光博客
宝玉的分享
宝玉的分享
小众软件
小众软件
罗磊的独立博客
有赞技术团队
有赞技术团队
Stack Overflow Blog
Stack Overflow Blog

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Caching in ASP.NET Core
Donia Shaban · 2026-05-20 · via DEV Community

Caching in ASP.NET Core — A Complete Guide

Caching is the single most impactful performance optimization you can apply to a web app. The idea is simple: instead of recomputing or re-fetching the same data on every request, you store it somewhere fast and serve it from there. ASP.NET Core gives you three distinct caching mechanisms, each operating at a different layer of your app. Let's break each one down.


Why do we actually use caching?

A 100ms delay causes 7% fewer conversions — meaning if your checkout page takes even one tenth of a second longer, you statistically lose customers. Amazon calculated this years ago and it still holds. A 3-second load time loses 40% of users entirely — they leave before the page finishes.

The reason caching is the go-to fix is the bottleneck breakdown the PDF shows: 60% of slowness comes from the database, 25% from slow API calls, and only 15% from memory/other issues. Caching directly attacks the biggest problem — the DB. Instead of hitting SQL Server 1000 times for the same product data, you hit it once and serve the cached result 999 times. That's where the "80–90% DB load reduction" figure comes from.

The Netflix example (70% startup time reduction) is real — they heavily cache user profiles, recommendation lists, and content metadata in Redis so that when you open the app, almost nothing needs a live DB query.

Where do the actual problems come from?

Database (60% of problems) — This is the classic N+1 query problem, missing indexes, fetching entire tables when you need 3 rows, and hitting the DB on every single request for data that barely changes (like a list of product categories). Caching fixes this directly.

APIs (25% of problems) — Calling external services (payment gateways, weather APIs, third-party data) on every request. If you call an exchange rate API on every page load, you're adding 200–500ms of network latency every time. Cache that response for 5 minutes and the latency disappears.

Memory (15% of problems) — This is actually caused by bad caching, not a lack of it. When you cache without expiration policies or cache huge objects carelessly, you put pressure on the GC (Garbage Collector). The server starts spending CPU time collecting memory instead of serving requests. This is why the "set expiration policies" rule matters so much — cache is not free RAM, it's borrowed RAM.

The performance metrics from the PDF are also worth internalizing for your own apps: target average response time under 200ms, keep CPU below 70%, memory below 80%, and HTTP 5xx errors below 0.1%. Those are the numbers you'd put on a production monitoring dashboard.


1. In-Memory Cache (IMemoryCache)

What it is: Data is stored directly in the server process's RAM. It's the fastest cache available — a dictionary lookup with no network round-trip.

Where it lives: Inside your application process. If you restart the server, the cache is gone. If you have multiple servers behind a load balancer, each server has its own isolated cache.

Best for: Single-server apps, frequently read but rarely changed data (e.g., lookup tables, config values, user roles).

in_memory_cache_flow

How to use it:

// Program.cs
builder.Services.AddMemoryCache();

// In your service
public class ProductService(IMemoryCache cache, AppDbContext db)
{
    public async Task<Product?> GetProductAsync(int id)
    {
        if (cache.TryGetValue($"product:{id}", out Product? cached))
            return cached;

        var product = await db.Products.FindAsync(id);

        var options = new MemoryCacheEntryOptions()
            .SetAbsoluteExpiration(TimeSpan.FromMinutes(10))
            .SetSlidingExpiration(TimeSpan.FromMinutes(2));

        cache.Set($"product:{id}", product, options);
        return product;
    }
}

Enter fullscreen mode Exit fullscreen mode

Key concepts to know:

  • Absolute expiration — the item is always removed after X time, no matter how much it's accessed.
  • Sliding expiration — the timer resets every time the item is accessed; it's evicted only if nobody touches it for X time.
  • Eviction policies — when RAM gets tight, ASP.NET Core uses LRU (Least Recently Used) to drop items. You can also set CacheItemPriority to protect critical entries.
  • Cache Stampede — if 100 requests arrive simultaneously on a cache miss, they all hit the DB at once. Use GetOrCreateAsync or a SemaphoreSlim lock to handle this safely.

2. Distributed Cache (IDistributedCache)

What it is: Data is stored in an external shared store — Redis being the most common choice — that all your servers can reach. When you scale out to 3 servers, they all read from and write to the same cache.
Where it lives: Outside your app process, usually Redis or SQL Server.

Best for: Multi-server deployments, session data, anything that must be consistent across servers, large-scale apps.

distributed_cache_flow

How to use it (with Redis):

// Program.cs
builder.Services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = "localhost:6379";
    options.InstanceName = "MyApp:";
});

// In your service
public class ProductService(IDistributedCache cache, AppDbContext db)
{
    public async Task<Product?> GetProductAsync(int id)
    {
        var key = $"product:{id}";
        var cached = await cache.GetStringAsync(key);

        if (cached is not null)
            return JsonSerializer.Deserialize<Product>(cached);

        var product = await db.Products.FindAsync(id);

        var options = new DistributedCacheEntryOptions()
            .SetAbsoluteExpirationRelativeToNow(TimeSpan.FromMinutes(10));

        await cache.SetStringAsync(key, JsonSerializer.Serialize(product), options);
        return product;
    }
}

Enter fullscreen mode Exit fullscreen mode

Notice that unlike IMemoryCache, the distributed cache stores bytes/strings, so you serialize/deserialize yourself. This is the price of network storage — but the payoff is consistency across all your servers.


3. Output Caching & Response Caching

These two are often confused. They both cache the HTTP response, but they work at different layers.

Response Caching — sets HTTP cache headers (Cache-Control, Expires) that tell the client or proxy to cache the response. The server itself doesn't store anything; it just instructs whoever's asking.

Output Caching (ASP.NET Core 7+) — the server caches the full HTTP response and serves it directly on repeat requests, before your controller action even executes. No business logic, no DB query.

output_vs_response_cache_fixed

Output Caching setup:

// Program.cs
builder.Services.AddOutputCache(options =>
{
    options.AddBasePolicy(b => b.Cache());
    options.AddPolicy("Products", b => b.Cache()
        .Expire(TimeSpan.FromMinutes(5))
        .Tag("products-tag"));
});

app.UseOutputCache();

// In your controller
[HttpGet("products")]
[OutputCache(PolicyName = "Products")]
public async Task<IActionResult> GetProducts() { ... }

// Invalidation: purge a specific tag
await _cache.EvictByTagAsync("products-tag", token);

Enter fullscreen mode Exit fullscreen mode

Response Caching setup:

// Program.cs
builder.Services.AddResponseCaching();
app.UseResponseCaching();

// In your controller
[HttpGet("products")]
[ResponseCache(Duration = 300, VaryByQueryKeys = new[] { "category" })]
public async Task<IActionResult> GetProducts(string category) { ... }

Enter fullscreen mode Exit fullscreen mode

The ResponseCache attribute tells the framework to emit Cache-Control: public, max-age=300 headers. The browser or CDN does the actual caching.


Quick Comparison

Feature In-Memory Distributed Output Cache Response Cache
Where stored Server RAM Redis / SQL Server Server (middleware) Client / Proxy
Survives restart? No Yes No (unless backed by Redis) Yes (in browser)
Multi-server safe? No Yes Yes N/A
Caches Any object Bytes / strings Full HTTP response Full HTTP response
Granularity Fine (per key) Fine (per key) Per endpoint/route Per URL
Best for Fast lookups, small data Sessions, scaled apps Read-heavy API endpoints Public, static-ish content