nam vo
nam vo

Reputation: 3457

How to iterate through MemoryCache in asp.net core?

There's no available method in IMemoryCache that allows to iterate through each cached item. My project is small, I don't want to use other options like Redis.

namepsace    Microsoft.Extensions.Caching.Memory{
        public static class CacheExtensions
    {
        public static object Get(this IMemoryCache cache, object key);
        public static TItem Get<TItem>(this IMemoryCache cache, object key);
        public static TItem GetOrCreate<TItem>(this IMemoryCache cache, object key, Func<ICacheEntry, TItem> factory);
        [AsyncStateMachine(typeof(CacheExtensions.<GetOrCreateAsync>d__9<>))]
        public static Task<TItem> GetOrCreateAsync<TItem>(this IMemoryCache cache, object key, Func<ICacheEntry, Task<TItem>> factory);
        public static TItem Set<TItem>(this IMemoryCache cache, object key, TItem value);
        public static TItem Set<TItem>(this IMemoryCache cache, object key, TItem value, DateTimeOffset absoluteExpiration);
        public static TItem Set<TItem>(this IMemoryCache cache, object key, TItem value, TimeSpan absoluteExpirationRelativeToNow);
        public static TItem Set<TItem>(this IMemoryCache cache, object key, TItem value, IChangeToken expirationToken);
        public static TItem Set<TItem>(this IMemoryCache cache, object key, TItem value, MemoryCacheEntryOptions options);
        public static bool TryGetValue<TItem>(this IMemoryCache cache, object key, out TItem value);
    }
}

https://github.com/aspnet/Caching/blob/dev/src/Microsoft.Extensions.Caching.Memory/MemoryCache.cs

Upvotes: 9

Views: 19154

Answers (3)

Alon S
Alon S

Reputation: 195

You could use private properties and reflection to gain access (with the risks it entails). This example assumes your cache instance is stored in 'appGlobals.memoryCache'

 var cacheEntriesCollectionDefinition = typeof(MemoryCache).GetProperty("EntriesCollection", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
 var cacheEntriesCollection = cacheEntriesCollectionDefinition?.GetValue(appGlobals.memoryCache) as dynamic;

        if (cacheEntriesCollection != null)
        {
            foreach (var cacheItem in cacheEntriesCollection)
            {
                var cacheKey = cacheItem.GetType().GetProperty("Key").GetValue(cacheItem) as string;

            }
        }
    

Upvotes: 1

Lapenkov Vladimir
Lapenkov Vladimir

Reputation: 3218

For large project this is a bit an awkward way. I'd recommend you to use a wrapper class MemoryCacheManager and register it as Singleton. https://gist.github.com/vlapenkov/0a66c40221f9c56d12eb0420fb7cef77

use

_manager.Get("key", ()=>"value") // to set a key,

_manager.GetKeys() // get all keys

_manager.Remove("key") //remove one key

_manager.Clear() //remove all keys

Upvotes: 6

Tseng
Tseng

Reputation: 64307

You should cache two type of items.

  1. You cache your properties as they are, abc.xyz-{0}.
  2. Second cache a list of property under the main key name, abc.xyz

Sample Code:

cache.Set("abc.xyz-name", name, TimeSpan.FromMinutes(30));
cache.Set("abc.xyz-lastname", lastname, TimeSpan.FromMinutes(30));
cache.Set("abc.xyz-birthday", birthday, TimeSpan.FromMinutes(30));
cache.Set("abc.xyz", new List<string> { "abc.xyz-name", "abc.xyz-lastname", "abc.xyz-birthday" }, TimeSpan.FromMinutes(30));

and when deleting:

var keys = cache.Get<List<string>>("abc.xyz");
foreach(var key in keys)
    cache.Remove(key);
cache.remove("abc.xyz");

Most of the services use IDistributedCache (in your case MemoryDistributedCache when registered - which again injects IMemoryCache which is MemoryCache class).

In a distributed cache you can't iterate over all keys as there are potentially millions of keys and this would significantly reduce the performance of the cached service if you could/would iterate over it.

So the above solution is also friendly and ready for the case when you replace your memory cache with a distributed cache, such as Redis.

Upvotes: 24

Related Questions