Caching is one of the most important techniques for improving the performance of your ASP.NET Core Web API. If you are new to APIs, first understand What Is Web API in .NET? Explained Simply (ASP.NET Core Web API) before learning advanced concepts like caching. It reduces unnecessary database calls, improves response times, and makes your application more scalable. In this post, you will learn how to implement three different types of caching in ASP.NET Core 8 Web API — 1.IMemoryCache 2. Distributed Cache (Redis), and 3. Response Caching — with step-by-step examples and proper project structure.
Introduction to Caching
Caching is the process of storing frequently accessed data temporarily so that future requests can be served faster. In ASP.NET Core Web API applications, caching reduces database calls, improves performance, and makes applications more scalable.
Caching Strategies in ASP.NET Core 8
- IMemoryCache: Stores data in server memory (single server).
- Distributed Cache (Redis, SQL Server): Stores cache across multiple servers like Redis and SQL server.
- Response Caching: Caches entire HTTP responses for endpoints.
Why Caching is Important
Without caching, every API request hits the database every time, which can slow down your application and increase server load. Caching ensures:
- Faster response time for users
- Reduced database load
- Improved scalability for high-traffic applications
- Enhanced user experience
- Improve the application performance.
Types of Caching in ASP.NET Core
1. IMemoryCache
IMemoryCache stores data in the application’s memory. It’s perfect for small or single-server applications.
Pros:
- Simple to use
- No external dependencies
Cons:
- Only works for single-server apps
- Cache is lost if the app restarts
When to Use IMemoryCache
- Frequently accessed data
- Expensive DB queries
- External API calls
- Configuration or lookup data
- Single server application
- Fast access
- Small-to-medium data
A Few Things to Keep in Mind In IMemoryCache
- The cache lives inside your application. If you are running your app on multiple servers, each server will have its own separate cache — they don’t share data with each other.
- Since everything is stored in memory, the cached data disappears when the app restarts.
- Because of this,
IMemoryCacheis not a good fit for distributed or cloud environments. In those cases, you should useIDistributedCachewith Redis or SQL server so all servers can share the same cached data.
Code Example (Step-by-Step):
Now we see the code example step by step:-
Step 1 – Create a New ASP.NET Core 8 Web API
dotnet new webapi -n MemoryCacheDemo
cd MemoryCacheDemoIf you want a complete CRUD example with database integration, read Learn How to Create ASP.NET Core 8 Web API – Step-by-Step CRUD with SQL Server & EF Core.
Step 2 – Register Memory Cache Service
Open Program.cs
IMemoryCache is already available in ASP.NET Core, but we need to register it.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
// Register Memory Cache
builder.Services.AddMemoryCache();
var app = builder.Build();
app.MapControllers();
app.Run();Now Memory caching is now enabled.
Step 3 – Create a Sample Service (Simulating Database)
Create a folder –Services
Create file: ProductService.cs
namespace MemoryCacheDemo.Services;
public class ProductService
{
public async Task<List<string>> GetProductsAsync()
{
// Simulate slow database call
await Task.Delay(3000);
return new List<string>
{
"Laptop",
"Keyboard",
"Mouse",
"Monitor"
};
}
}Now register the service in Program.cs
builder.Services.AddScoped<ProductService>();Step 4 – Inject IMemoryCache into Controller
Create a controller:
Controllers/ProductController.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
using MemoryCacheDemo.Services;
namespace MemoryCacheDemo.Controllers;
[ApiController]
[Route("api/[controller]")]
public class ProductController : ControllerBase
{
private readonly IMemoryCache _cache;
private readonly ProductService _productService;
public ProductController(IMemoryCache cache, ProductService productService)
{
_cache = cache;
_productService = productService;
}
[HttpGet]
public async Task<IActionResult> GetProducts()
{
string cacheKey = "productList";
if (!_cache.TryGetValue(cacheKey, out List<string> products))
{
// Data not in cache → fetch from service
products = await _productService.GetProductsAsync();
var cacheOptions = new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromMinutes(5))
.SetSlidingExpiration(TimeSpan.FromMinutes(2));
_cache.Set(cacheKey, products, cacheOptions);
}
return Ok(products);
}
}Cleaner Alternative – Using GetOrCreateAsync (Recommended)
While the above approach works perfectly, ASP.NET Core provides a cleaner and more readable way to implement caching using GetOrCreateAsync().
Instead of manually checking with TryGetValue(), we can simplify the code:
[HttpGet]
public async Task<IActionResult> GetProducts()
{
string cacheKey = "productList";
var products = await _cache.GetOrCreateAsync(cacheKey, async entry =>
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5);
entry.SlidingExpiration = TimeSpan.FromMinutes(2);
return await _productService.GetProductsAsync();
});
return Ok(products);
}Why This Is Better
- Automatically checks if cache exists
- Creates and stores data if missing
- Reduces boilerplate code
- Cleaner and more maintainable
This approach is recommended in real-world applications.
Step 5 – Test the API
Run the project:
dotnet runCall:
GET https://localhost:5001/api/productWhat happens?
- First request → takes 3 seconds (simulated DB call)
- Second request → instant response (served from cache)
After:
- 5 minutes → cache expires (absolute expiration)
- 2 minutes of inactivity → cache expires (sliding expiration)
Understanding Expiration Types
1. Absolute Expiration
.SetAbsoluteExpiration(TimeSpan.FromMinutes(5))Cache expires after 5 minutes — no matter what.
2. Sliding Expiration
.SetSlidingExpiration(TimeSpan.FromMinutes(2))Cache resets expiration timer every time it is accessed.
Best practice: Use both together.
2. Distributed Caching in ASP.NET Core 8 Web API
What is Distributed Caching?
Distributed caching stores data in an external cache store instead of application memory.
For secure APIs using caching, you should also implement authentication using How to Implement JWT Authentication in ASP.NET Core 8 Web API (Step-by-Step).
That means:
- Shared across multiple servers
- Works in load-balanced environments
- Survives application restarts
- Slightly slower than in-memory (network call involved)
Distributed Cache allows sharing cache across multiple servers, ideal for scalable apps. Redis is the most popular choice.
Pros:
- Works in load-balanced environments
- Persistent across app restarts
Cons:
- Requires external setup
Popular Distributed Cache Providers
- Redis (Most common)
- SQL Server
- NCache
- Azure Cache for Redis
Code Example (Step-by-Step)
Now we see code example step by step about distributed caching.
Step 1 – Install Redis Package
dotnet add package Microsoft.Extensions.Caching.StackExchangeRedisThis package allows ASP.NET Core to connect to Redis as a distributed cache provider.
Step 2 – Configure Distributed Cache in Program.cs
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = "localhost:6379";
options.InstanceName = "DemoInstance_";
});Configuration→ Redis server addressInstanceName→ Prefix for cache keys
Make sure Redis server is running before testing the API.
Step 3 – Inject IDistributedCache into Controller
In distributed caching, unlike IMemoryCache, we cannot store objects directly. Redis (or any distributed cache) only stores strings or byte arrays, so we need to serialize objects to JSON before storing, and deserialize when retrieving.
Here’s how you inject IDistributedCache into your controller:
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Distributed;
using System.Text.Json;
using MemoryCacheDemo.Services;
namespace MemoryCacheDemo.Controllers;
[ApiController]
[Route("api/[controller]")]
public class ProductController : ControllerBase
{
private readonly IDistributedCache _cache;
private readonly ProductService _productService;
public ProductController(IDistributedCache cache, ProductService productService)
{
_cache = cache;
_productService = productService;
}
}Key Points:
- _cache is your connection to Redis.
- You will use _cache.GetStringAsync() and _cache.SetStringAsync() to get and set cached data.
- Objects must be serialized/deserialized (we’ll use JsonSerializer).
Step 4 – Implement Distributed Caching in Controller
Now, create an endpoint to fetch products using distributed caching:
[HttpGet("distributed")]
public async Task<IActionResult> GetProductsDistributed()
{
string cacheKey = "productList";
// Try to get cached data
var cachedData = await _cache.GetStringAsync(cacheKey);
if (string.IsNullOrEmpty(cachedData))
{
// Cache miss → fetch data from service
var products = await _productService.GetProductsAsync();
var options = new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5),
SlidingExpiration = TimeSpan.FromMinutes(2)
};
// Serialize and store in Redis
await _cache.SetStringAsync(cacheKey, JsonSerializer.Serialize(products), options);
return Ok(products);
}
// Cache hit → deserialize JSON
var cachedProducts = JsonSerializer.Deserialize<List<string>>(cachedData);
return Ok(cachedProducts);
}Step 5 – Test the API
Run the project:
dotnet runCall the endpoint:
GET https://localhost:5001/api/product/distributed- First request: slow (fetches from
ProductService) - Second request: fast (served from Redis cache)
- Cache expires after 5 minutes (absolute) or 2 minutes of inactivity (sliding)
Response Caching in ASP.NET Core 8 Web API
What is Response Caching?
Response caching stores HTTP responses (usually GET requests) so that:
- Repeated requests return cached content without hitting the server logic.
- Reduces server processing and improves API performance.
- Very fast
- Reduces CPU and DB load
- Works mainly for GET requests
- Cannot cache dynamic content (like POST results)
When to Use
- For GET endpoints that return data that doesn’t change frequently.
- When multiple clients request the same data.
- In combination with client-side caching using headers.
Code Example (Step-by-Step)
Step 1 – Enable Response Caching Middleware
In Program.cs, add the middleware:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
// Enable Response Caching
builder.Services.AddResponseCaching();
var app = builder.Build();
app.UseResponseCaching(); // Add middleware
app.MapControllers();
app.Run();Note: UseResponseCaching() must be called before mapping controllers.
Step 2 – Add ResponseCache Attribute to Controller/Endpoint
Create a GET endpoint that caches responses:
using Microsoft.AspNetCore.Mvc;
using MemoryCacheDemo.Services;
namespace MemoryCacheDemo.Controllers;
[ApiController]
[Route("api/[controller]")]
public class ProductController : ControllerBase
{
private readonly ProductService _productService;
public ProductController(ProductService productService)
{
_productService = productService;
}
[HttpGet("response")]
[ResponseCache(Duration = 60, Location = ResponseCacheLocation.Client)]
public async Task<IActionResult> GetProductsResponseCache()
{
// Simulate slow database call
var products = await _productService.GetProductsAsync();
return Ok(products);
}
}Step 3 – How It Works
Duration = 60→ cache the response for 60 secondsLocation = ResponseCacheLocation.Client→ tells the client (browser, API caller) to cache the response- On repeated requests within 60 seconds, the API doesn’t process the request again — the cached response is returned
You can also use:
ResponseCacheLocation.Any→ server + client cachingNoStore = true→ disable caching for sensitive data
Step 4 – Test the Endpoint
Call:
GET https://localhost:5001/api/product/response- First request → slow (simulated DB call)
- Second request within 60 seconds → instant (served from cached response)
Comparison of Caching Types in ASP.NET Core 8 Web API
| Feature | Memory Cache | Distributed Cache | Response Cache |
|---|---|---|---|
| Storage Location | Application memory | External server (Redis, SQL, etc.) | HTTP response (server/client) |
| Scope | Single server | Shared across multiple servers | Server + client (HTTP) |
| Persistence | Lost on app restart | Survives app restarts | Depends on headers and duration |
| Speed | Very fast | Fast (network call) | Very fast |
| Object Storage | Can store objects directly | Must serialize objects (JSON/byte[]) | Entire HTTP response |
| Best For | Expensive DB queries, frequently used data | Scalable apps, load-balanced or microservices | GET endpoints with static/slow-changing data |
| Pros | Easy to implement, fast | Shared cache, survives restarts, scalable | Reduces server processing, instant GET responses |
| Cons | Not shared across servers, lost on restart | Requires external setup, serialization needed | Limited to HTTP responses, mostly GET only |
| Typical Use Case | Small apps, single server | Cloud apps, multi-instance microservices | Public API endpoints, client caching, CDN-friendly |
This table summarizes the three types of caching in ASP.NET Core 8. Use Memory Cache for single-server apps, Distributed Cache for scalable multi-server scenarios, and Response Cache for caching GET responses to improve API performance.
Conclusion
Implementing caching in ASP.NET Core 8 Web API is not just a performance optimization — it’s a necessity for building scalable and responsive applications.
In this guide, we explored different techniques for Caching in ASP.NET Core 8 Web API to improve performance and scalability.
- IMemoryCache is perfect for simple, single-server apps where speed matters and data is small.
- Distributed Cache with Redis ensures your application can scale across multiple servers, keeping data consistent and persistent even if an instance restarts.
- Response Caching reduces redundant processing by storing entire HTTP responses, making repeated GET requests lightning-fast.
Choosing the right caching strategy depends on your application’s architecture and the type of data you are working with. In many cases, combining multiple caching types can give the best results: for example, using IMemoryCache for frequently accessed data and Response Caching for public GET endpoints.
To understand how .NET evolved to support modern features like caching, read Difference Between .NET Framework, .NET Core & .NET 8.
The key takeaway: think about where your data lives, who needs it, and how often it changes — then pick the caching approach that fits best. Done right, caching makes your API faster, lighter on the server, and ready to handle real-world traffic without headaches.
Related Blogs You Might Like
- Difference between .NET framework, .NET Core & .NET 8 – Learn different .NET versions.
- What is .NET Full Stack Development? Beginner Guide – Understand the full .NET full stack development.
- What Is Web API in .NET? Explained Simply (ASP.NET Core Web API) – Understand and learn web API.
- What Is ASP.NET MVC Framework? Architecture, Features, Life Cycle & Example – Learn ASP.NET MVC
- How to Implement JWT Authentication In ASP.NET Core 8 Web API (Step-by-Step) – JWT Authentication
- Learn How to create ASP.NET Core 8 Web API – Step-by-Step CRUD with SQL Server & EF Core – CRUD Operation in .NET Core Web API

