问题
I can find a remove
method to remove an object from IMemoryCache
by its key. Is there a way to reset the whole cache and remove all objects?
Edit:
How to clear MemoryCache?
Dispose method provided in the link gives me an exception in asp.net 5. ObjectDisposedException: Cannot access a disposed object.
Object name: 'Microsoft.Extensions.Caching.Memory.MemoryCache'.
回答1:
https://docs.microsoft.com/en-us/aspnet/core/performance/caching/memory Section Cache dependencies
Using a CancellationTokenSource allows multiple cache entries to be evicted as a group
This code worked for me:
public class CacheProvider
{
private static CancellationTokenSource _resetCacheToken = new CancellationTokenSource();
private readonly IMemoryCache _innerCache;
/* other methods and constructor removed for brevity */
public T Set<T>(object key, T value)
{
/* some other code removed for brevity */
var options = new MemoryCacheEntryOptions().SetPriority(CacheItemPriority.Normal).SetAbsoluteExpiration(typeExpiration);
options.AddExpirationToken(new CancellationChangeToken(_resetCacheToken.Token));
_innerCache.Set(CreateKey(type, key), value, options);
return value;
}
public void Reset()
{
if (_resetCacheToken != null && !_resetCacheToken.IsCancellationRequested && _resetCacheToken.Token.CanBeCanceled)
{
_resetCacheToken.Cancel();
_resetCacheToken.Dispose();
}
_resetCacheToken = new CancellationTokenSource();
}
}
回答2:
There are a lot of hacks to do this. If you have the right IMemoryCache, you can use Compact(1.0)
, otherwise this hack works:
This code will work (tested in unit tests and on production on .NET core 2.2):
PropertyInfo prop = cache.GetType().GetProperty("EntriesCollection", BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.NonPublic | BindingFlags.Public);
object innerCache = prop.GetValue(cache);
MethodInfo clearMethod = innerCache.GetType().GetMethod("Clear", BindingFlags.Instance | BindingFlags.Public);
clearMethod.Invoke(innerCache, null);
回答3:
The answer as of RC1 is that you can't do it out of the box from what I've read and been told (I did read on GitHub that there maybe a way to create triggers to facilitate this that are coming).
Currently, you are provided Get, Set and Remove. I see your options as:
- Create a cache manager wrapper that will track all of your keys, you can then remove those items in bulk as you see fit. I'm not in love with this but it would work. Of course, if you're not the one controlling the adding there could be things in the cache you are unaware of (you could compare your count to it's count to see). If you cast IMemoryCache as MemoryCache you can get the Count property which is exposed.
- Fork the assembly and expose the Keys and/or add a method to remove those items. There is an underlying dictionary that holds the keys. I did this, compiled it, create a Nuget package for it and then replaced the RC1 version just to see if I could (and it worked). Not sure if this is the right way but here's the commit to my fork, I just added a read only property where I dumped the keys to an object list (the keys are stored as objects). As with past MemoryCache implementations, if you exposed the keys they could be stale after they're dumped, but if you're just using them to clear all then that shouldn't matter.
https://github.com/blakepell/Caching/commit/165ae5ec13cc51c44a6007d6b88bd9c567e1d724
I posted this issue last night trying to figure out if there's a good way to inspect what's in the cache specifically (asking why don't we have a way to). If you don't ask you'll never know if it would have mattered so I figured why not.
https://github.com/aspnet/Caching/issues/149
回答4:
my solution was to set new expiration date to all the items in cache to 1 millisecond. Then they expired and hence cache flush.
回答5:
My solution was to create a wrapper which re-expose existing few methods and add a missing method by replacing MemoryCache object with a brand new one. Worked just fine for me. Code is below:
public interface IMyMemoryCache : IMemoryCache
{
void Reset();
}
public class MyMemoryCache: IMyMemoryCache
{
IMemoryCache _memoryCache;
public MyMemoryCache()
{
Reset();
}
public void Dispose()
{
_memoryCache.Dispose();
}
public bool TryGetValue(object key, out object value)
{
return _memoryCache.TryGetValue(key, out value);
}
public ICacheEntry CreateEntry(object key)
{
return _memoryCache.CreateEntry(key);
}
public void Remove(object key)
{
_memoryCache.Remove(key);
}
public void Reset()
{
_memoryCache = new MemoryCache(new MemoryCacheOptions());
}
}
来源:https://stackoverflow.com/questions/34406737/how-to-remove-all-objects-reset-from-imemorycache-in-asp-net-core