web-dev-qa-db-fra.com

MemoryCache Empty: renvoie null après avoir été défini

J'ai un problème avec une application MVC 3 qui utilise le nouveau .NET 4 System.Runtime.Caching MemoryCache. Je remarque qu'après un temps apparemment imprévisible, il arrête la mise en cache des trucs et agit comme s'il était vide. Considérez ce morceau de code que j'ai pris directement à partir d'une vue de test dans ASP.NET MVC:

MemoryCache.Default.Set("myname","fred", new CacheItemPolicy() { SlidingExpiration = new TimeSpan(0,5,0) });
Response.Write(MemoryCache.Default["myname"]);

Lorsque cela fonctionne, "fred" est prévisible imprimé. Toutefois, lorsque le problème commence à se produire, malgré la Set(), la valeur de MemoryCache.Default["myname"] Est nulle. Je peux le prouver en définissant un point d'arrêt sur la ligne Response.Write() et en définissant directement et en lisant à partir du cache à l'aide de la fenêtre immédiate - Cela ne le définira tout simplement pas et reste nul! Le seul moyen de le faire fonctionner à nouveau est alors de provoquer un recyclage AppDomain.

Curieusement, je peux provoquer le problème de se produire lorsque l'application fonctionne normalement en interrompant la ligne Response.Write() et en exécutant MemoryCache.Default.Dispose(). Après cela, MemoryCache.Default n'est pas null lui-même (pourquoi est-ce?), Mais ne sauvegardera rien défini dessus. Cela ne cause aucune erreur, mais ne sauvera rien.

Quelqu'un peut-il vérifier cela et expliquer? Comme je crois l'avoir découvert, lorsque l'application cesse de fonctionner d'elle-même, quelque chose se débarrasse de MemoryCache.Default, Mais ce n'est pas moi!


MISE À JOUR

Eh bien, j'en ai marre de ce problème maintenant! CLRProfiler ne semble pas fonctionner avec MVC 3. L'outil CLR de SciTech était bon - tout comme RedGate ANTS. Mais tout ce qu'ils m'ont dit, c'est que l'objet MemoryCache est éliminé par quelque chose ! J'ai également prouvé (via une impression d'horodatage) qu'un PartialView sur ma page qui devrait être mis en cache (spécifié par OutputCacheAttribute) cesse d'être mis en cache après quelques minutes - il commence à se rafraîchir à chaque appel à la page. Juste pour clarifier l'environnement, j'exécute directement sur le serveur IIS 7.5 sur mon poste de développement exécutant Win 7 Ultimate. Les outils de mémoire mentionnés ci-dessus suggèrent que j'utilise seulement environ 9 Mo de mémoire en termes de objets en jeu.

En désespoir de cause, j'ai changé mon code de mise en cache pour rechercher d'abord un HttpContext ambiant auquel se connecter et utiliser sa fonctionnalité de mise en cache, si elle est disponible. Les premiers tests montrent que cela est fiable, mais cela ressemble à un méchant hack.

J'ai l'impression que MemoryCache et OutputCache ne sont pas garantis pour fonctionner avec MVC 3 ...

51
James McCormack

Alors, voici quelques nouvelles. Nous avons examiné cela et OUI, c'est un bogue dans .NET 4.

La bonne nouvelle est qu'il a été corrigé dans .NET 4.5, donc si vous le pouvez, mettez à jour votre installation vers .NET 4.5 et vous êtes solide.

L'autre bonne nouvelle est que ce correctif a été porté en arrière sur .NET 4 et sera disponible en tant que QFE (correctif rapide ... un correctif unique que vous appliquerez) # 578315. Il a été rétroporté/corrigé il y a quelques jours à peine et devrait être retiré dès que possible. J'essaierai d'avoir une date exacte, mais c'est bientôt.

L'autre autre bonne nouvelle est qu'il existe une solution de contournement pour cela sur .NET 4 avant le QFE. La solution de contournement est bizarre, mais elle pourrait vous débloquer.

using (ExecutionContext.SuppressFlow())     {
          // Create memory cache instance under disabled execution context flow
         return new YourCacheThing.GeneralMemoryCache(…);
}

J'espère que cela t'aides.

MISE À JOUR: Le correctif est http://support.Microsoft.com/kb/282884 et vous pouvez le demander ici: https://support.Microsoft.com/contactus/emailcontact. aspx? scid = sw;% 5BLN% 5D; 1422

68
Scott Hanselman

Nous avons le meme probleme. Je confirme qu'après un certain temps, le cache a été supprimé. Son champ privé _disposed est devenu 1. Je suis sûr que je n'ai pas d'appel à cache.Dispose dans mon code. Mais quand j'ai regardé le code de MemoryCache avec Reflector, j'ai vu que, dans le constructeur, il souscrit à deux événements

domain.DomainUnload += eventHandler;
domain.UnhandledException += exceptionEventHandler;

private void OnAppDomainUnload(object unusedObject, EventArgs unusedEventArgs)
{
  this.Dispose();
}

private void OnUnhandledException(object sender, UnhandledExceptionEventArgs eventArgs)
{
  if (!eventArgs.IsTerminating)
    return;
  this.Dispose();
}

Ces deux gestionnaires d'événements ont appelé à Dispose. Peut être après un certain recyclage de domaine en IIS il provoque le déchargement du domaine, mais garde le cache en mémoire (je ne suis pas sûr si c'est possible).

6
Dima

J'ai éprouvé exactement les mêmes symptômes. J'ai finalement réussi à utiliser la classe System.Web.Cache à la place et à me connecter à HttpContext.Cache. Cela fonctionne parfaitement depuis 3 jours.

3
Grant

Voir aussi ces liens liés au même problème.

MemoryCache est supprimé après PollingInterval lorsqu'il est utilisé dans WebApp en mode Pipeline intégré

http://connect.Microsoft.com/VisualStudio/feedback/details/764911/memorycache-gets-disposed-after-pollinginterval-when-used-in-webapp-in-integrated-pipeline-mode

MemoryCache se trouve dans l'état supprimé comme par magie

http://social.msdn.Microsoft.com/Forums/en-US/netfxbcl/thread/1233ffb3-6480-431b-94ca-1190f96cf5f6

2
Alex Nolasco

MemoryCache expulsera automatiquement les éléments s'il atteint sa limite de mémoire. Cela pourrait se produire dans votre cas, avez-vous beaucoup d'éléments dans le cache?

Vous pouvez contrôler les limites avec configuration . Par défaut, il optimise en fonction de la mémoire disponible.

L'appel de Dispose arrêtera certainement l'instance de MemoryCache car elle nettoiera toutes les ressources non gérées prêtes à être éliminées. Vous ne devez appeler Dispose que si vous n'avez plus l'intention d'utiliser MemoryCache. Je ne pense pas que ce soit nécessaire le problème dans votre cas, sauf lorsque vous l'appelez.

1
TheCodeKing