← Back to Articles         

ASP.NET Core In-Memory Caching

Published on 16 Apr 2026     4 min read Web API
C Sharp Caching in .NET

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:

  1. Reads the product from the original source.

  2. Stores it in memory.

  3. 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 IMemoryCache interface 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.

 

← Back to Articles