What is In-Memory Caching?
In-memory caching stores frequently used data inside the Web API server’s memory (RAM).
Instead of repeatedly reading the same data from a database or external API, the application first checks the cache.
Request → Check Cache
↓
Found → Return cached data
Missing → Read database → Store in cache → Return data
This approach is called the Cache-Aside Pattern.
Why do we need it?
-
Reduces database calls
-
Improves API response time
-
Reduces server and database load
-
Useful for frequently accessed data
-
Suitable for data that does not change often
Step 1: Register Memory Cache
Add AddMemoryCache() in Program.cs:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
// Register in-memory caching
builder.Services.AddMemoryCache();
var app = builder.Build();
app.MapControllers();
app.Run();
Step 2: Create the Controller
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private readonly IMemoryCache _cache;
private static readonly Dictionary<int, string> products = new()
{
{ 1, "Laptop" },
{ 2, "Mobile" },
{ 3, "Keyboard" }
};
public ProductsController(IMemoryCache cache)
{
_cache = cache;
}
[HttpGet("{id}")]
public IActionResult GetProduct(int id)
{
string cacheKey = $"product-{id}";
// Try to retrieve the product from the cache
if (!_cache.TryGetValue(cacheKey, out string? product))
{
// Cache miss: retrieve from the original source
if (!products.TryGetValue(id, out product))
{
return NotFound($"Product ID {id} was not found.");
}
var cacheOptions = new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromSeconds(30))
.SetSlidingExpiration(TimeSpan.FromSeconds(10));
// Store the product in cache
_cache.Set(cacheKey, product, cacheOptions);
return Ok(new
{
ProductId = id,
ProductName = product,
Source = "Original source"
});
}
// Cache hit
return Ok(new
{
ProductId = id,
ProductName = product,
Source = "Memory cache"
});
}
}
How it works
Call the endpoint:
GET /api/products/1
First request: cache miss
The cache does not contain product-1.
The API:
-
Reads the product from the original source.
-
Stores it in memory.
-
Returns the product.
{
"productId": 1,
"productName": "Laptop",
"source": "Original source"
}
Second request: cache hit
If the same endpoint is called before expiration, the product is returned directly from memory:
{
"productId": 1,
"productName": "Laptop",
"source": "Memory cache"
}
Expiration types
.SetAbsoluteExpiration(TimeSpan.FromSeconds(30))
Absolute expiration removes the entry 30 seconds after it was created, even when it is frequently accessed.
.SetSlidingExpiration(TimeSpan.FromSeconds(10))
Sliding expiration removes the entry if it is not accessed for 10 consecutive seconds. Every cache hit resets this inactivity period.
When both are configured, the cache expires when the first applicable limit is reached.
Removing cached data
When a product is updated or deleted, remove its old cached value:
[HttpPut("{id}")]
public IActionResult UpdateProduct(int id, string productName)
{
if (!products.ContainsKey(id))
{
return NotFound();
}
products[id] = productName;
string cacheKey = $"product-{id}";
// Remove stale data
_cache.Remove(cacheKey);
return Ok("Product updated and cache removed.");
}
The next GET request reads the updated product from the source and caches it again.
Key points
-
In-memory caching stores frequently accessed data in the application server’s RAM.
-
Register caching services using
AddMemoryCache(). -
Inject the
IMemoryCacheinterface through dependency injection. -
Use
TryGetValue()to check whether data exists in the cache. -
Use
Set()to add data to the cache. -
Use
Remove()to delete outdated cached data. -
Configure expiration using
MemoryCacheEntryOptions:
var cacheOptions = new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromSeconds(30))
.SetSlidingExpiration(TimeSpan.FromSeconds(10));
-
Absolute expiration removes the entry after 30 seconds, even when it is accessed frequently.
-
Sliding expiration removes the entry when it is not accessed for 10 consecutive seconds.
-
When both are configured, the cache entry expires when either limit is reached first.
-
Store the value with its expiration options:
_cache.Set(cacheKey, value, cacheOptions);
-
Remove or refresh cached data whenever the original data changes.
-
In-memory caching reduces database calls and improves API performance.
-
Cached data is lost when the application restarts.
-
Each application server maintains its own separate in-memory cache.
-
Avoid caching sensitive, frequently changing or very large data.
-
For multiple application servers, prefer a distributed cache such as Redis.