Skip to main content
This example demonstrates two caching strategies in ASP.NET Core: custom in-memory caching with configurable expiration times, and response caching using the ResponseCache attribute.

Overview

Caching improves application performance by storing frequently accessed data in memory, reducing database queries and computation time.

Caching Strategies

Custom Memory Cache

Provides fine-grained control over cache expiration with custom timeout settings.

Response Cache (Distributed)

Uses HTTP caching headers to cache entire action results on the client side.

Complete Implementation

1

Configure Caching Services

Register caching services in your application startup.
Program.cs
var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllersWithViews();

builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession();

builder.Services.AddMemoryCache();

var app = builder.Build();

// Configure middleware
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseSession();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=UploadFiles}/{action=SubirFile}/{id?}")
    .WithStaticAssets();

app.Run();
Key Services:
  • AddMemoryCache(): Enables custom in-memory caching
  • AddDistributedMemoryCache(): Enables distributed caching (for response cache)
  • AddSession(): Enables session state (uses distributed cache)
2

Create the Caching Controller

The controller demonstrates both caching approaches with dependency injection.
Controllers/CachingController.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;

namespace MvcNetCoreUtilidades.Controllers
{
    public class CachingController : Controller
    {
        private IMemoryCache memoryCache;

        public CachingController(IMemoryCache memoryCache)
        {
            this.memoryCache = memoryCache;
        }

        public IActionResult Index()
        {
            return View();
        }

        public IActionResult MemoriaPersonalizada(int? tiempo)
        {
            if (tiempo == null)
            {
                tiempo = 60;
            }
            string fecha = DateTime.Now.ToLongDateString() + "--" + DateTime.Now.ToLongTimeString();
            if (this.memoryCache.Get("FECHA") == null)
            {
                MemoryCacheEntryOptions options = new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromSeconds(tiempo.Value));
                this.memoryCache.Set("FECHA", fecha, options);
                ViewData["MENSAJE"] = "Fecha almacenada correctamente";
                ViewData["FECHA"] = this.memoryCache.Get("FECHA");
            }
            else
            {
                fecha = this.memoryCache.Get<string>("FECHA");
                ViewData["MENSAJE"] = "Fecha recuperada correctamente";
                ViewData["FECHA"] = fecha;
            }
            return View();
        }

        [ResponseCache(Duration = 15, Location = ResponseCacheLocation.Client)]
        public IActionResult MemoriaDistribuida()
        {
            string fecha = DateTime.Now.ToLongDateString() + "--" + DateTime.Now.ToLongTimeString();
            ViewData["FECHA"] = fecha;
            return View();
        }
    }
}
See CachingController.cs:19 and CachingController.cs:42
3

Create the Views

Custom Memory Cache View:
Views/Caching/MemoriaPersonalizada.cshtml
<h1>Memoria Personalizada</h1>

<p>
    <a asp-controller="Caching" asp-action="MemoriaPersonalizada">Actualizar página</a>
</p>
<p>
    <a asp-controller="Caching" asp-action="MemoriaPersonalizada" asp-route-tiempo="15">Actualizar página 15 sg</a>
</p>
<p>
    <a asp-controller="Caching" asp-action="MemoriaPersonalizada" asp-route-tiempo="30">Actualizar página 30sg</a>
</p>
<h2 style="color: blue">@ViewData["MENSAJE"]</h2>
<h2 style="color: red">@ViewData["FECHA"]</h2>
Response Cache View:
Views/Caching/MemoriaDistribuida.cshtml
<h1>Memoria Distribuida</h1>

<p><a asp-controller="Caching" asp-action="MemoriaDistribuida">Actualizar página</a></p>
<h2 style="color: blue">@ViewData["FECHA"]</h2>

How It Works

Custom Memory Cache

if (this.memoryCache.Get("FECHA") == null)
{
    // Cache miss - store new value
}
else
{
    // Cache hit - retrieve existing value
}
Workflow:
  1. Check if cache key exists
  2. If not exists (cache miss): Store value with expiration time
  3. If exists (cache hit): Retrieve cached value
  4. After expiration: Cache is automatically cleared, next request stores new value

Response Cache

[ResponseCache(Duration = 15, Location = ResponseCacheLocation.Client)]
public IActionResult MemoriaDistribuida()
{
    // This response is cached on the client for 15 seconds
    string fecha = DateTime.Now.ToLongDateString() + "--" + DateTime.Now.ToLongTimeString();
    ViewData["FECHA"] = fecha;
    return View();
}
Workflow:
  1. First request: Server processes and sends response with cache headers
  2. Subsequent requests (within 15 seconds): Browser uses cached response
  3. After 15 seconds: Browser requests fresh data from server

Usage Examples

Custom Expiration Times

The MemoriaPersonalizada action accepts a tiempo parameter:
  • Default (60 seconds): /Caching/MemoriaPersonalizada
  • 15 seconds: /Caching/MemoriaPersonalizada?tiempo=15
  • 30 seconds: /Caching/MemoriaPersonalizada?tiempo=30
  • Custom: /Caching/MemoriaPersonalizada?tiempo=120

Testing Cache Behavior

  1. Navigate to /Caching/MemoriaPersonalizada?tiempo=15
  2. Note the displayed date/time (red text)
  3. Refresh the page within 15 seconds → Same date/time displayed (cache hit)
  4. Wait 15+ seconds and refresh → New date/time displayed (cache expired)

Cache Comparison

FeatureCustom Memory CacheResponse Cache
LocationServer memoryClient browser
ConfigurationProgrammatic (C# code)Attribute-based
Expiration ControlCustom per requestFixed duration
StorageIMemoryCache serviceHTTP headers
Use CaseData objects, computed valuesFull page responses
Default TimeoutNo default (must specify)No default

Advanced Options

Memory Cache Entry Options

var options = new MemoryCacheEntryOptions()
    .SetAbsoluteExpiration(TimeSpan.FromMinutes(5))  // Absolute expiration
    .SetSlidingExpiration(TimeSpan.FromMinutes(2))   // Sliding expiration
    .SetPriority(CacheItemPriority.High)             // Priority
    .RegisterPostEvictionCallback(MyCallback);        // Callback on eviction

Response Cache Locations

// Cache on client only
[ResponseCache(Duration = 60, Location = ResponseCacheLocation.Client)]

// Cache on server only  
[ResponseCache(Duration = 60, Location = ResponseCacheLocation.Server)]

// Cache on both client and server
[ResponseCache(Duration = 60, Location = ResponseCacheLocation.Any)]

// No caching
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]

Best Practices

Use custom memory cache when:
  • You need fine-grained control over cache expiration
  • Caching data objects or computed results
  • Different cache durations per user/request
Use response cache when:
  • Caching entire page responses
  • Content doesn’t change frequently
  • Reducing server load for public pages
Memory cache considerations:
  • Stored in server memory (lost on restart)
  • Consumes server resources
  • Not shared across multiple servers (unless using distributed cache)
Performance tip: For production apps with multiple servers, consider using distributed caching with Redis or SQL Server instead of in-memory cache.

CachingController

Complete API reference for caching controller

Caching Utility

Learn about caching features and options

Build docs developers (and LLMs) love