ASP.NET
MVC
OutputCacheAttribute
Caching
External Cache Providers

ASP.NET MVC OutputCacheAttribute with external cache providers

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

OutputCacheAttribute in ASP.NET MVC can do more than cache content in-process. Because it sits on top of the ASP.NET output-caching infrastructure, you can back it with a custom OutputCacheProvider and store cached responses in an external system such as Redis or a distributed cache. That is especially useful in a web farm, where in-memory cache on one server does not help another server.

What OutputCacheAttribute Actually Caches

At the MVC level, OutputCacheAttribute caches rendered action output according to rules such as duration and variation.

A basic action looks like this:

csharp
1[OutputCache(Duration = 60, VaryByParam = "id")]
2public ActionResult Details(int id)
3{
4    var model = repository.GetProduct(id);
5    return View(model);
6}

This means the generated output can be reused for 60 seconds, with separate cache entries for different id values.

By default, the backing provider may be in-memory on the current server. In a single-node app that may be enough. In a multi-node app, it often is not.

Why Use an External Provider

An external output-cache provider helps when:

  • you run multiple web servers behind a load balancer
  • you need cache entries shared across instances
  • app restarts should not wipe every cached page immediately
  • cache memory should live outside the IIS worker process

This does not change how you decorate the controller action very much. It changes where the cached entries are stored and retrieved.

Implement a Custom OutputCacheProvider

ASP.NET lets you implement a provider by inheriting from OutputCacheProvider.

csharp
1using System;
2using System.Collections.Concurrent;
3using System.Web.Caching;
4
5public class DemoOutputCacheProvider : OutputCacheProvider
6{
7    private static readonly ConcurrentDictionary<string, object> Store = new();
8
9    public override object Get(string key)
10    {
11        Store.TryGetValue(key, out var value);
12        return value;
13    }
14
15    public override void Set(string key, object entry, DateTime utcExpiry)
16    {
17        Store[key] = entry;
18    }
19
20    public override void Remove(string key)
21    {
22        Store.TryRemove(key, out _);
23    }
24
25    public override object Add(string key, object entry, DateTime utcExpiry)
26    {
27        return Store.TryAdd(key, entry) ? entry : Get(key);
28    }
29}

This example uses an in-memory dictionary only to demonstrate the interface. A real external provider would forward Get, Set, and Remove calls to Redis, AppFabric, NCache, or another shared cache.

Register the Provider in web.config

Once you have a provider, register it with ASP.NET output caching.

xml
1<caching>
2  <outputCache defaultProvider="ExternalOutputCache">
3    <providers>
4      <add name="ExternalOutputCache"
5           type="MyApp.Caching.DemoOutputCacheProvider, MyApp" />
6    </providers>
7  </outputCache>
8</caching>

Now OutputCacheAttribute can use that provider through the underlying output-cache infrastructure.

Keep Variation Rules Correct

Externalizing the cache does not remove the need for correct cache keys. Duration, VaryByParam, VaryByCustom, and location rules still determine whether a cached response is safe to reuse.

For example:

csharp
1[OutputCache(Duration = 120, VaryByParam = "category;page")]
2public ActionResult List(string category, int page = 1)
3{
4    var model = repository.GetProducts(category, page);
5    return View(model);
6}

If variation settings are wrong, the provider works perfectly while still serving the wrong content to users.

Be Careful With Authenticated or User-Specific Output

Output caching is dangerous when the response includes user-specific or sensitive data. An external provider makes this more scalable, not safer by itself.

Good candidates:

  • product pages
  • public listing pages
  • read-heavy anonymous content

Risky candidates:

  • account pages
  • personalized dashboards
  • anything that varies by authenticated identity unless keyed very carefully

The caching strategy must match the data sensitivity.

Distinguish Output Caching From Data Caching

If the expensive part of the request is data retrieval rather than HTML rendering, sometimes it is better to cache data and render per request instead of caching whole responses.

Use output caching when the rendered response is stable and expensive enough to justify page-level reuse. Use data caching when the page composition still needs per-request logic even though the underlying data is reusable.

Common Pitfalls

A common mistake is assuming that using an external provider automatically fixes bad cache variation rules. It does not. Wrong keys simply become wrong keys in a bigger cache.

Another issue is caching authenticated or personalized pages without enough variation, which can leak one user’s output to another.

Developers also sometimes implement the provider interface but ignore expiration semantics. If the external store does not respect utcExpiry, the cache can become stale far longer than intended.

Finally, be sure the operational cost is worth it. Distributed output caching adds complexity, and some applications get more value from simpler data caching.

Summary

  • 'OutputCacheAttribute can work with external cache providers through OutputCacheProvider.'
  • This is useful for multi-server deployments where in-process cache is not enough.
  • Register the provider in web.config and keep action-level variation settings accurate.
  • Be especially careful with personalized or authenticated responses.
  • Choose distributed output caching only when page-level reuse is worth the extra infrastructure.

Course illustration
Course illustration

All Rights Reserved.