How to Implement Caching in ASP.NET Core

Published on April 15

โšก How to Implement Caching in ASP.NET Core (With Timeouts & Cache Updates)

Performance matters. Whether you're building an e-commerce site, a content-heavy portal, or a data-driven dashboard, caching is one of the fastest ways to reduce response times and improve scalability.

In this guide, youโ€™ll learn how to implement caching in ASP.NET Core using:

  • In-Memory Caching
  • Cache Expiration (Absolute & Sliding)
  • Manual Cache Updates (Cache Busting)
  • Async Caching with GetOrCreateAsync

๐Ÿง  What is Caching?

Caching stores frequently accessed data in memory (or distributed storage) so that future requests are served faster. ASP.NET Core provides a clean, flexible API for caching out-of-the-box.



๐Ÿ›  Step 1: Set Up In-Memory Caching

First, add the in-memory cache service in Program.cs or Startup.cs:

builder.Services.AddMemoryCache();

Inject IMemoryCache into your controller or service:

public class WeatherService
{
    private readonly IMemoryCache _cache;

    public WeatherService(IMemoryCache cache)
    {
        _cache = cache;
    }
}

๐Ÿงช Step 2: Basic Caching with Timeout

Use SetAbsoluteExpiration to store data for a fixed time.

public async Task<string> GetWeatherAsync()
{
    var cacheKey = "weather-today";

    if (!_cache.TryGetValue(cacheKey, out string weather))
    {
        // Simulate slow external API call
        await Task.Delay(1000);
        weather = $"Sunny at {DateTime.Now}";

        var cacheEntryOptions = new MemoryCacheEntryOptions()
            .SetAbsoluteExpiration(TimeSpan.FromMinutes(5));

        _cache.Set(cacheKey, weather, cacheEntryOptions);
    }

    return weather;
}

๐Ÿ’ก Key Takeaway: SetAbsoluteExpiration ensures the cache is valid for a specific time, regardless of access frequency.



๐Ÿ” Step 3: Use Sliding Expiration

Use SetSlidingExpiration to reset the timeout on each access:

var cacheEntryOptions = new MemoryCacheEntryOptions()
    .SetSlidingExpiration(TimeSpan.FromMinutes(2)); // Extends 2 min from last access

This is great for frequently accessed data that should expire only after being idle.



๐Ÿš€ Step 4: Cache Data Asynchronously (GetOrCreateAsync)

Instead of manual TryGetValue, use the fluent GetOrCreateAsync pattern:

public async Task<string> GetNewsAsync()
{
    return await _cache.GetOrCreateAsync("headline", async entry =>
    {
        entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(3);
        await Task.Delay(500); // Simulate I/O
        return $"Top headline at {DateTime.Now}";
    });
}

โœ… Cleaner and recommended approach for async data.



๐Ÿ”„ Step 5: Update (Bust) the Cache

To manually update (or bust) a cache item:

public void UpdateWeatherCache(string newWeather)
{
    _cache.Set("weather-today", newWeather, new MemoryCacheEntryOptions
    {
        AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5)
    });
}

Or remove it completely:

_cache.Remove("weather-today");

This is helpful when data changes externally (e.g., admin updates content).



โš™ Full Example: Caching in a Controller

[ApiController]
[Route("[controller]")]
public class WeatherController : ControllerBase
{
    private readonly IMemoryCache _cache;

    public WeatherController(IMemoryCache cache)
    {
        _cache = cache;
    }

    [HttpGet]
    public async Task<string> Get()
    {
        return await _cache.GetOrCreateAsync("weather", async entry =>
        {
            entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(2);
            await Task.Delay(1000); // Simulate slow fetch
            return $"Weather fetched at {DateTime.Now}";
        });
    }

    [HttpPost("refresh")]
    public IActionResult Refresh()
    {
        _cache.Remove("weather");
        return Ok("Cache cleared");
    }
}

๐Ÿงฐ Bonus: When to Use Distributed Cache

For web farms or containerized apps, switch to:

  • IDistributedCache (backed by Redis, SQL Server, etc.)
  • Use NuGet package: Microsoft.Extensions.Caching.StackExchangeRedis

This lets you share cache across multiple app instances.



โœ… Summary

Feature Use Case IMemoryCache Simple, single-server apps Absolute expiration Expire after a fixed time Sliding expiration Expire after inactivity GetOrCreateAsync Simplify async caching logic cache.Remove(key) Bust cache manually IDistributedCache Shared cache for scale-out deployments

๐Ÿ“š Further Reading


Want to see a follow-up post on Redis caching with IDistributedCache, output caching, or custom cache eviction strategies? Just say the word!