web-dev-qa-db-fra.com

Comment supprimer tous les objets (réinitialiser) d'IMemoryCache dans le noyau ASP.NET

Je peux trouver une méthode remove pour supprimer un objet de IMemoryCache par sa clé. Existe-t-il un moyen de réinitialiser l'ensemble du cache et de supprimer tous les objets?

Éditer:

Comment effacer MemoryCache? La méthode Dispose fournie dans le lien me donne une exception dans asp.net 5. ObjectDisposedException: Cannot access a disposed object. Object name: 'Microsoft.Extensions.Caching.Memory.MemoryCache'.

24
eadam

https://docs.Microsoft.com/en-us/aspnet/core/performance/caching/memory Section Dépendances du cache

L'utilisation d'un CancellationTokenSource permet d'expulser plusieurs entrées de cache en tant que groupe

Ce code a fonctionné pour moi:

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();
    }
}
30
aleha

Il y a beaucoup de hacks pour le faire. Si vous avez le bon IMemoryCache, vous pouvez utiliser Compact(1.0), sinon ce hack fonctionne:

Ce code fonctionnera (testé dans des tests unitaires et en production sur .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);
4
jjxtra

La réponse à partir de RC1 est que vous ne pouvez pas le faire hors de la boîte à partir de ce que j'ai lu et qui m'a été dit (j'ai lu sur GitHub qu'il y avait peut-être un moyen de créer des déclencheurs pour faciliter cela à venir).

Actuellement, vous obtenez Get, Set et Remove. Je vois vos options comme:

  1. Créez un wrapper de gestionnaire de cache qui suivra toutes vos clés, vous pouvez ensuite supprimer ces éléments en bloc comme bon vous semble. Je ne suis pas amoureux de ça mais ça marcherait. Bien sûr, si vous n'êtes pas celui qui contrôle l'ajout, il peut y avoir des choses dans le cache que vous ignorez (vous pouvez comparer votre nombre à son nombre à voir). Si vous convertissez IMemoryCache en MemoryCache, vous pouvez obtenir la propriété Count qui est exposée.
  2. Fourchez l'assemblage et exposez les clés et/ou ajoutez une méthode pour supprimer ces éléments. Il existe un dictionnaire sous-jacent qui contient les clés. Je l'ai fait, compilé, créé un package Nuget pour cela, puis remplacé la version RC1 juste pour voir si je pouvais (et cela a fonctionné). Je ne sais pas si c'est la bonne façon, mais voici le commit de ma fourchette, j'ai juste ajouté une propriété en lecture seule où j'ai vidé les clés dans une liste d'objets (les clés sont stockées en tant qu'objets). Comme avec les implémentations antérieures de MemoryCache, si vous exposez les clés, elles peuvent être périmées après leur vidage, mais si vous les utilisez simplement pour effacer tout, cela ne devrait pas avoir d'importance.

https://github.com/blakepell/Caching/commit/165ae5ec13cc51c44a6007d6b88bd9c567e1d724

J'ai publié ce problème hier soir en essayant de déterminer s'il existe un bon moyen d'inspecter spécifiquement ce qui se trouve dans le cache (en demandant pourquoi nous n'avons pas de moyen de le faire). Si vous ne demandez pas, vous ne saurez jamais si cela aurait été important, alors j'ai pensé pourquoi pas.

https://github.com/aspnet/Caching/issues/149

2
b.pell

Ma solution a été de créer un wrapper qui réexpose quelques méthodes existantes et d'ajouter une méthode manquante en remplaçant l'objet MemoryCache par un tout nouveau. A très bien fonctionné pour moi. Le code est ci-dessous:

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());
    }
}
1
tgralex

ma solution a été de définir une nouvelle date d'expiration pour tous les éléments du cache à 1 milliseconde. Ensuite, ils ont expiré et, par conséquent, le vidage du cache.

1
DarthVader

Ce code peut vous aider si vous utilisez le MemoryCache standard. Documentation: https://docs.Microsoft.com/en-us/aspnet/core/performance/caching/memory?view=aspnetcore-3.1#memorycachecompact

_cache.Compact(1.0);
1
scribe