IMemoryCache

Implementation

The first thing we need to do is to add nuget package, of course:

dotnet add package Microsoft.Extensions.Caching.Memory 

To successfully use the library, we need to add it through Dependency Injection in Program.cs class:

builder.Services.AddMemoryCache();

And you can use it with practically no configuration. I will inject it directly into the controller that .NET created for me by default.

private readonly IMemoryCache _cacheService;

public WeatherForecastController(IMemoryCache cacheService)
{
    _cacheService = cacheService;
}

And now in the GET method where we capture the weather forecast from various weather stations, we will include cached ones. We understand that the weather will not change every minute, so we can cache the weather forecast values for a while.

[HttpGet(Name = "GetWeatherForecast")]
public List<WeatherForecast> Get()
{
    if (!_cacheService.TryGetValue("MyCacheKey", out List<WeatherForecast> weathersFromCache))
    {
        var weathers = Enumerable.Range(1, 300).Select(index => new WeatherForecast
        {
            Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = Summaries[Random.Shared.Next(Summaries.Length)]
        }).ToList();

        _cacheService.Set<List<WeatherForecast>>("MyCacheKey", weathers);

        return weathers;
    }

    return weathersFromCache;
}

Explanation: • Cache Check _casheService.TryGetValue...: - It attempts to retrieve a cached value associated with the key "MyCacheKey" (Don't hardcode this). - If the value is found in the cache, it is output into weathersFromCache. - The method TryGetValue returns true if the key was found in the cache, and false otherwise. • Cache Miss Handling: - If the cache does not contain the key (i.e., TryGetValue returned false), the code block inside the if statement is executed. - A new list of WeatherForecast objects is created by generating 300 forecasts. - This newly created list is then stored in the cache with the key "MyCacheKey". • Returning the Result: If the data was retrieved from the cache, it is returned directly.If the data was not in the cache (cache miss), the newly generated list is returned.

IMemoryCache Expiration Time

In the provided code snippet, there is no explicit cache expiration time set. This means the cache entry for "MyCacheKey" will remain in the cache indefinitely, or until it is explicitly removed or replaced, or if the cache evicts it due to memory pressure. To set an explicit cache expiration time, you would need to modify the code where the cache entry is set. This involves using MemoryCacheEntryOptions to specify the desired expiration policy. There are two common ways to set expiration: • Absolute Expiration: The cache entry will expire after a specified duration regardless of whether it is accessed or not. • Sliding Expiration: The cache entry will expire after a specified duration if it is not accessed within that timeframe. Each access to the cache entry resets the expiration timer. Let's see both in action. Setting Absolute Expiration Here's how you can modify the code to set an absolute expiration of, for example, 30 minutes:

var cacheEntryOptions = new MemoryCacheEntryOptions
{
    AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30) // Cache for 30 minutes
};

_cacheService.Set<List<WeatherForecast>>("MyCacheKey", weathers, cacheEntryOptions);

When to use? 1. When data has a known and fixed expiry time. 2. When it's important to refresh data at predictable intervals, regardless of how often it is accessed. Setting Sliding Expiration And here's how you can set a sliding expiration of 30 minutes:

var cacheEntryOptions = new MemoryCacheEntryOptions
{
    SlidingExpiration = TimeSpan.FromMinutes(30) // Cache for 30 minutes
};

_cacheService.Set<List<WeatherForecast>>("MyCacheKey", weathers, cacheEntryOptions);

When to use? 1. When the importance of the data is based on how recently it has been accessed. 2. To automatically manage memory by removing less frequently accessed items. Combining Both You can also combine both absolute and sliding expirations for more complex caching scenarios:

var cacheEntryOptions = new MemoryCacheEntryOptions
{
    AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1), // Absolute expiration of 1 hour
    SlidingExpiration = TimeSpan.FromMinutes(30) // Sliding expiration of 30 minutes
};

_cacheService.Set<List<WeatherForecast>>("MyCacheKey", weathers, cacheEntryOptions);

In this combined scenario, the cache entry will expire if it's not accessed for 30 minutes, but it will also expire unconditionally after 1 hour from when it was added to the cache.

IMemoryCache MemoryCacheEntryOptions

MemoryCacheEntryOptions is a versatile class in .NET Core's caching infrastructure that allows you to configure various aspects of how individual items are cached in memory. This configuration plays a crucial role in optimizing the performance and resource management of your application. Here's a more detailed look at what you can set using MemoryCacheEntryOptions besides Expiration Settings: 1. Priority CacheItemPriority: Determines the priority of a cache entry. During memory pressure, entries with lower priority may be removed first to free up space. Values range from Low to NeverRemove. 2. Size Specifies the size of the cache entry, which is considered when the cache size limit is set on the IMemoryCache instance. This helps in controlling the memory footprint of the cache. 3. Callbacks and Tokens • PostEvictionCallbacks: A list of callbacks that will be executed after the cache entry is removed. This is useful for performing actions like logging or cleanup operations. • RegisterPostEvictionCallback: A method to add a post-eviction callback directly to the cache entry options. • ExpirationTokens: These allow the cache entry to be dependent on external triggers. For example, you can link a cache entry to a file using a FileChangeToken, and the cache entry will be evicted if the file changes. 4. Change Tokens AddExpirationToken(IChangeToken token): This method allows you to add a custom implementation of IChangeToken to trigger cache evictions. It's a powerful feature for creating complex cache invalidation logic based on external changes. Example usage:

var cacheEntryOptions = new MemoryCacheEntryOptions()
{
    AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(60), // Expires in 60 minutes
    SlidingExpiration = TimeSpan.FromMinutes(15), // Reset expiration to 15 minutes if accessed
    Priority = CacheItemPriority.High, // High priority
    Size = 1024 // Size of the entry is 1024 units
};

cacheEntryOptions.RegisterPostEvictionCallback(
    (key, value, reason, state) =>
    {
        Console.WriteLine($"Cache item {key} was removed due to {reason}.");
    }
);

_memoryCache.Set("MyCacheKey", myObject, cacheEntryOptions);

Last updated