Overview of caching in ASP.NET Core (original) (raw)

Important

This information relates to a pre-release product that may be substantially modified before it's commercially released. Microsoft makes no warranties, express or implied, with respect to the information provided here.

For the current release, see the .NET 9 version of this article.

By Rick Anderson and Tom Dykstra

In-memory caching

In-memory caching uses server memory to store cached data. This type of caching is suitable for a single server or multiple servers using session affinity. Session affinity is also known as sticky sessions. Session affinity means that the requests from a client are always routed to the same server for processing.

For more information, see Cache in-memory in ASP.NET Core and Troubleshoot Azure Application Gateway session affinity issues.

Distributed Cache

Use a distributed cache to store data when the app is hosted in a cloud or server farm. The cache is shared across the servers that process requests. A client can submit a request that's handled by any server in the group if cached data for the client is available. ASP.NET Core works with SQL Server, Redis, and NCache distributed caches.

For more information, see Distributed caching in ASP.NET Core.

HybridCache

The HybridCache API bridges some gaps in the IDistributedCache and IMemoryCache APIs. HybridCache is an abstract class with a default implementation that handles most aspects of saving to cache and retrieving from cache.

Features

HybridCache has the following features that the other APIs don't have:

To see the relative simplicity of the HybridCache API, compare code that uses it to code that uses IDistributedCache. Here's an example of what using IDistributedCache looks like:

public class SomeService(IDistributedCache cache)
{
    public async Task<SomeInformation> GetSomeInformationAsync
        (string name, int id, CancellationToken token = default)
    {
        var key = $"someinfo:{name}:{id}"; // Unique key for this combination.
        var bytes = await cache.GetAsync(key, token); // Try to get from cache.
        SomeInformation info;
        if (bytes is null)
        {
            // Cache miss; get the data from the real source.
            info = await SomeExpensiveOperationAsync(name, id, token);

            // Serialize and cache it.
            bytes = SomeSerializer.Serialize(info);
            await cache.SetAsync(key, bytes, token);
        }
        else
        {
            // Cache hit; deserialize it.
            info = SomeSerializer.Deserialize<SomeInformation>(bytes);
        }
        return info;
    }

    // This is the work we're trying to cache.
    private async Task<SomeInformation> SomeExpensiveOperationAsync(string name, int id,
        CancellationToken token = default)
    { /* ... */ }
}

That's a lot of work to get right each time, including things like serialization. And in the "cache miss" scenario, you could end up with multiple concurrent threads, all getting a cache miss, all fetching the underlying data, all serializing it, and all sending that data to the cache.

Here's equivalent code using HybridCache:

public class SomeService(HybridCache cache)
{
    public async Task<SomeInformation> GetSomeInformationAsync
        (string name, int id, CancellationToken token = default)
    {
        return await cache.GetOrCreateAsync(
            $"someinfo:{name}:{id}", // Unique key for this entry.
            async cancel => await SomeExpensiveOperationAsync(name, id, cancel),
            token: token
        );
    }
}

The code is simpler and the library provides stampede protection and other features that IDistributedCache doesn't.

Compatibility

The HybridCache library supports older .NET runtimes, down to .NET Framework 4.7.2 and .NET Standard 2.0.

Additional resources

For more information, see the following resources:

Response caching

The Response caching middleware:

To test response caching, use Fiddler, or another tool that can explicitly set request headers. Setting headers explicitly is preferred for testing caching. For more information, see Troubleshooting.

For more information, see Response caching in ASP.NET Core.

Output caching

The output caching middleware enables caching of HTTP responses. Output caching differs from response caching in the following ways:

For more information, see Output caching middleware in ASP.NET Core.

Cache Tag Helper

Cache the content from an MVC view or Razor Page with the Cache Tag Helper. The Cache Tag Helper uses in-memory caching to store data.

For more information, see Cache Tag Helper in ASP.NET Core MVC.

Distributed Cache Tag Helper

Cache the content from an MVC view or Razor Page in distributed cloud or web farm scenarios with the Distributed Cache Tag Helper. The Distributed Cache Tag Helper uses SQL Server, Redis, or NCache to store data.

For more information, see Distributed Cache Tag Helper in ASP.NET Core.

In-memory caching

In-memory caching uses server memory to store cached data. This type of caching is suitable for a single server or multiple servers using session affinity. Session affinity is also known as sticky sessions. Session affinity means that the requests from a client are always routed to the same server for processing.

For more information, see Cache in-memory in ASP.NET Core and Troubleshoot Azure Application Gateway session affinity issues.

Distributed Cache

Use a distributed cache to store data when the app is hosted in a cloud or server farm. The cache is shared across the servers that process requests. A client can submit a request that's handled by any server in the group if cached data for the client is available. ASP.NET Core works with SQL Server, Redis, and NCache distributed caches.

For more information, see Distributed caching in ASP.NET Core.

HybridCache

The HybridCache API bridges some gaps in the IDistributedCache and IMemoryCache APIs. HybridCache is an abstract class with a default implementation that handles most aspects of saving to cache and retrieving from cache.

Features

HybridCache has the following features that the other APIs don't have:

To see the relative simplicity of the HybridCache API, compare code that uses it to code that uses IDistributedCache. Here's an example of what using IDistributedCache looks like:

public class SomeService(IDistributedCache cache)
{
    public async Task<SomeInformation> GetSomeInformationAsync
        (string name, int id, CancellationToken token = default)
    {
        var key = $"someinfo:{name}:{id}"; // Unique key for this combination.
        var bytes = await cache.GetAsync(key, token); // Try to get from cache.
        SomeInformation info;
        if (bytes is null)
        {
            // Cache miss; get the data from the real source.
            info = await SomeExpensiveOperationAsync(name, id, token);

            // Serialize and cache it.
            bytes = SomeSerializer.Serialize(info);
            await cache.SetAsync(key, bytes, token);
        }
        else
        {
            // Cache hit; deserialize it.
            info = SomeSerializer.Deserialize<SomeInformation>(bytes);
        }
        return info;
    }

    // This is the work we're trying to cache.
    private async Task<SomeInformation> SomeExpensiveOperationAsync(string name, int id,
        CancellationToken token = default)
    { /* ... */ }
}

That's a lot of work to get right each time, including things like serialization. And in the "cache miss" scenario, you could end up with multiple concurrent threads, all getting a cache miss, all fetching the underlying data, all serializing it, and all sending that data to the cache.

Here's equivalent code using HybridCache:

public class SomeService(HybridCache cache)
{
    public async Task<SomeInformation> GetSomeInformationAsync
        (string name, int id, CancellationToken token = default)
    {
        return await cache.GetOrCreateAsync(
            $"someinfo:{name}:{id}", // Unique key for this entry.
            async cancel => await SomeExpensiveOperationAsync(name, id, cancel),
            token: token
        );
    }
}

The code is simpler and the library provides stampede protection and other features that IDistributedCache doesn't.

Compatibility

The HybridCache library supports older .NET runtimes, down to .NET Framework 4.7.2 and .NET Standard 2.0.

Additional resources

For more information, see the following resources:

Cache Tag Helper

Cache the content from an MVC view or Razor Page with the Cache Tag Helper. The Cache Tag Helper uses in-memory caching to store data.

For more information, see Cache Tag Helper in ASP.NET Core MVC.

Distributed Cache Tag Helper

Cache the content from an MVC view or Razor Page in distributed cloud or web farm scenarios with the Distributed Cache Tag Helper. The Distributed Cache Tag Helper uses SQL Server, Redis, or NCache to store data.

For more information, see Distributed Cache Tag Helper in ASP.NET Core.

Response caching

The Response caching middleware:

To test response caching, use Fiddler, or another tool that can explicitly set request headers. Setting headers explicitly is preferred for testing caching. For more information, see Troubleshooting.

Output caching

The output caching middleware enables caching of HTTP responses. Output caching differs from response caching in the following ways:

In-memory caching

In-memory caching uses server memory to store cached data. This type of caching is suitable for a single server or multiple servers using session affinity. Session affinity is also known as sticky sessions. Session affinity means that the requests from a client are always routed to the same server for processing.

For more information, see Cache in-memory in ASP.NET Core and Troubleshoot Azure Application Gateway session affinity issues.

Distributed Cache

Use a distributed cache to store data when the app is hosted in a cloud or server farm. The cache is shared across the servers that process requests. A client can submit a request that's handled by any server in the group if cached data for the client is available. ASP.NET Core works with SQL Server, Redis, and NCache distributed caches.

For more information, see Distributed caching in ASP.NET Core.

HybridCache

The HybridCache API bridges some gaps in the IDistributedCache and IMemoryCache APIs. HybridCache is an abstract class with a default implementation that handles most aspects of saving to cache and retrieving from cache.

Features

HybridCache has the following features that the other APIs don't have:

To see the relative simplicity of the HybridCache API, compare code that uses it to code that uses IDistributedCache. Here's an example of what using IDistributedCache looks like:

public class SomeService(IDistributedCache cache)
{
    public async Task<SomeInformation> GetSomeInformationAsync
        (string name, int id, CancellationToken token = default)
    {
        var key = $"someinfo:{name}:{id}"; // Unique key for this combination.
        var bytes = await cache.GetAsync(key, token); // Try to get from cache.
        SomeInformation info;
        if (bytes is null)
        {
            // Cache miss; get the data from the real source.
            info = await SomeExpensiveOperationAsync(name, id, token);

            // Serialize and cache it.
            bytes = SomeSerializer.Serialize(info);
            await cache.SetAsync(key, bytes, token);
        }
        else
        {
            // Cache hit; deserialize it.
            info = SomeSerializer.Deserialize<SomeInformation>(bytes);
        }
        return info;
    }

    // This is the work we're trying to cache.
    private async Task<SomeInformation> SomeExpensiveOperationAsync(string name, int id,
        CancellationToken token = default)
    { /* ... */ }
}

That's a lot of work to get right each time, including things like serialization. And in the "cache miss" scenario, you could end up with multiple concurrent threads, all getting a cache miss, all fetching the underlying data, all serializing it, and all sending that data to the cache.

Here's equivalent code using HybridCache:

public class SomeService(HybridCache cache)
{
    public async Task<SomeInformation> GetSomeInformationAsync
        (string name, int id, CancellationToken token = default)
    {
        return await cache.GetOrCreateAsync(
            $"someinfo:{name}:{id}", // Unique key for this entry.
            async cancel => await SomeExpensiveOperationAsync(name, id, cancel),
            token: token
        );
    }
}

The code is simpler and the library provides stampede protection and other features that IDistributedCache doesn't.

Compatibility

The HybridCache library supports older .NET runtimes, down to .NET Framework 4.7.2 and .NET Standard 2.0.

Additional resources

For more information, see the following resources:

Cache Tag Helper

Cache the content from an MVC view or Razor Page with the Cache Tag Helper. The Cache Tag Helper uses in-memory caching to store data.

For more information, see Cache Tag Helper in ASP.NET Core MVC.

Distributed Cache Tag Helper

Cache the content from an MVC view or Razor Page in distributed cloud or web farm scenarios with the Distributed Cache Tag Helper. The Distributed Cache Tag Helper uses SQL Server, Redis, or NCache to store data.

For more information, see Distributed Cache Tag Helper in ASP.NET Core.

Response caching

The Response caching middleware:

To test response caching, use Fiddler, or another tool that can explicitly set request headers. Setting headers explicitly is preferred for testing caching. For more information, see Troubleshooting.

Output caching

Output caching is available in .NET 7 and later.