Distributed caching int ASP.NET Core

ASP.NET Core has build in distributed caching functionality with multiple providers

Home DailyDrop

Daily Knowledge Drop

ASP.NET Core comes with the IDistributedCache interface, and a number of implementations to support distributed caching. The out of the box implementaions include In Memory, SQL Server, Redis and NCache - however if another implementation is required, a custom provider can also be fairly easily be written.


The need for distributed cache

Before getting to distributed cache we'll have a quick look at the non-distributed in memory cache implementation which also comes out of the box with ASP.NET Core. Configuring and leveraging this functionality is incredibly easy:

var builder = WebApplication.CreateBuilder(args);

// configure dependency injection with the in-memory cache
builder.Services.AddMemoryCache();

var app = builder.Build();

app.MapGet("/cache", (IMemoryCache cache) =>
{
    // try get a value with the key "hello" out the cache
    if(cache.TryGetValue("hello", out string result))
    {
        Console.WriteLine("Retrieved from cache");

        return result;
    }

    // if the value was not found in the cache
    // add it to the cache
    cache.Set("hello", "world");

    return "world";
});

app.Run();

Here, the IMemoryCache TryGetValue method is called to get get a value out of the cache by key. If no value is found, then the item is put into the cache and returned. This is a very simple example, with no cache expiry specified.

The in-memory cache will be entirely suitable if only one instance of an application is running - the cache is stored in the memory of that one instance of the application. However, if multiple instance of the application are running (in the cloud, or in containers) the in-memory cache is not shared across instances - each instance will have its own cached. This is where a distributed cache can be leveraged, with each application instance sharing the cache, and benefiting from the caching done by other instances.


Distributed cache

Configuring and using a distributed cache in ASP.NET Core is almost as easy as configuring a normal in-memory cache.

var builder = WebApplication.CreateBuilder(args);

// configure in-memory distributed cache
// which is good for testing, but is not truly 
// distributed
builder.Services.AddDistributedMemoryCache();

var app = builder.Build();

// inject IDistributedCache and not IMemoryCache
app.MapGet("/distributedcache", async (IDistributedCache cache) =>
{
    string result;

    // (Try) get the byte array value from the cache
    byte[] encodedResult = await cache.GetAsync("hello");
    // if a value was returned
    if(encodedResult != null)
    {
        Console.WriteLine("Retrieved from cache");

        // convert byte array to string and return
        result = Encoding.UTF8.GetString(encodedResult);
        return result;
    }

    // convert string to byte array 
    encodedResult = Encoding.UTF8.GetBytes("world");
    // and configure the cache options
    DistributedCacheEntryOptions options = new DistributedCacheEntryOptions()
        .SetSlidingExpiration(TimeSpan.FromSeconds(10));

    // add the value to the cache
    await cache.SetAsync("hello", encodedResult, options);

    return "world";

});

app.Run();

Usage

While IMemoryCache can store a string or object, IDistributedCache will only store a byte array. Additional processing has to be done to convert to and from a byte array when inserting and retrieving values from the cache. The IDistributedCache also doesn't have a TryGet method, only a Get method, which will return null if no value for the supplied key is found.


Configuration

The configuration of the in-memory distributed cache cache was simple (as seen above):

builder.Services.AddDistributedMemoryCache();

However, the configuration of the other implementations is not much more complicated. The SQL Server provider for example:

builder.Services.AddDistributedSqlServerCache(act =>
{
   act.SchemaName = "dbo";
   act.TableName = "AppCache";
   act.ConnectionString = builder.Configuration.GetConnectionString("DefaultDatabase");
});

The actual logic (the endpoint delegate method in the above example) can remain exactly as is.


Notes

Having a distributed cache is a key feature in many scalable applications, and the easy to configure and use, out of the box functionality provided by ASP.NET Core will be suitable for most application's needs.


References

Understanding & Implementing Caching in ASP.NET Core

Daily Drop 209: 24-11-2022

At the start of 2022 I set myself the goal of learning one new coding related piece of knowledge a day.
It could be anything - some.NET / C# functionality I wasn't aware of, a design practice, a cool new coding technique, or just something I find interesting. It could be something I knew at one point but had forgotten, or something completely new, which I may or may never actually use.

The Daily Drop is a record of these pieces of knowledge - writing about and summarizing them helps re-enforce the information for myself, as well as potentially helps others learn something new as well.
c# .net cache distributed distributedcache