Updates to MemoryCache in .NET 9 Preview 1

Introduction

In .NET 9 Preview 1, a new Keys property has been added to MemoryCache, allowing retrieval of cache keys. Additionally, a new overload of GetOrCreate (and its async counterpart) now accepts a MemoryCacheEntryOptions parameter.

Sample Usage

Keys Sample

New API:

public class MemoryCache
{
    public System.Collections.Generic.IEnumerable<object> Keys { get; }
}

Example without dependency injection:

Console.WriteLine("MemoryCache keys non-di sample");
var cache = new MemoryCache(new MemoryCacheOptions());
cache.Set("user:1:roles", "user,manager");
cache.Set("user:1:permission", "read,write");
cache.Set("user:2:roles", "user");
cache.Set("user:2:permission", "read");
foreach (var key in cache.Keys)
{
    Console.WriteLine(key.ToString());
    if (key is string keyStr && keyStr.StartsWith("user:2:"))
    {
        cache.Remove(key);
    }
}

Console.WriteLine("some keys had been removed");
foreach (var key in ((MemoryCache)cache).Keys)
{
    Console.WriteLine(key.ToString());
}

This example simulates clearing cache entries for user 2 and prints all cache keys.

Output: Keys non-DI sample output

Example with dependency injcetion:

Console.WriteLine("MemoryCache keys dependency injection sample");
using var services = new ServiceCollection()
    .AddMemoryCache()
    .BuildServiceProvider();
var cache = services.GetRequiredService<IMemoryCache>();
cache.Set("user:1:roles", "user,manager");
cache.Set("user:1:permission", "read,write");
cache.Set("user:2:roles", "user");
cache.Set("user:2:permission", "read");
foreach (var key in ((MemoryCache)cache).Keys)
{
    Console.WriteLine(key.ToString());
    if (key is string keyStr && keyStr.StartsWith("user:2:"))
    {
        cache.Remove(key);
    }
}

Console.WriteLine("some keys had been removed");
foreach (var key in ((MemoryCache)cache).Keys)
{
    Console.WriteLine(key.ToString());
}

Output: Keys DI sample output

Note that Keys is defined on MemoryCache, not on IMemoryCache, so casting is required when using DI.

GetOrCreate/GetOrCreateAsync Overload

New API:

namespace Microsoft.Extensions.Caching.Memory
{
    public static class CacheExtensions
    {
        public static TItem? GetOrCreate<TItem>(this IMemoryCache cache, object key, Func<ICacheEntry, TItem> factory, MemoryCacheEntryOptions? createOptions);
        public static Task<TItem?> GetOrCreateAsync<TItem>(this IMemoryCache cache, object key, Func<ICacheEntry, Task<TItem>> factory, MemoryCacheEntryOptions? createOptions);
    }
}

These overloads allow passing MemoryCacheEntryOptions to set expiration policies, simplifying the factory method.

Example usage:

Console.WriteLine("MemoryCache GetOrCreate with options sample");
using var services = new ServiceCollection()
    .AddMemoryCache()
    .BuildServiceProvider();
var cache = services.GetRequiredService<IMemoryCache>();

var key = "user:2:roles";
FetchValue();
Thread.Sleep(1000);
FetchValue();
Thread.Sleep(3000);
FetchValue();

void FetchValue()
{
    cache.GetOrCreate("no-expiration", _ =>
    {
        Console.WriteLine("fetch value from source for no-expiration key");
        return "user";
    });

    cache.GetOrCreate(key, _ =>
    {
        Console.WriteLine("fetch value from source");
        return "user";
    },
    new MemoryCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(3) });
}

Here, two cache entries are used for comparison: one without expiration and one with a 3-second absolute expiration. The output shows that the expiring entry is fetched twice (initial and after expiration), while the non-expiring entry is fetched only once.

Output: GetOrCreate with options output

References

Tags: MemoryCache .NET 9 Caching Preview

Posted on Sat, 03 Oct 2026 16:30:52 +0000 by SoreE yes