Nous avons récemment développé une nouvelle application Web ASP.NET MVC 4 (C#/Visual Studio). Après les tests et le débogage locaux, nous l'avons déployé en production, puis nous avons commencé à recevoir de plus en plus de messages de suivi de l'état de santé. Ceux-ci avaient différents messages d'exception:Stack Problème vide sur l'utilisation simultanée de l'application MVC
- Pile vide.
- La collection a été modifiée; l'opération d'énumération peut ne pas s'exécuter.
- L'article a déjà été ajouté. Clé dans le dictionnaire: 'ALL_HTTP' Clé ajoutée: 'ALL_HTTP' (autres clés également mentionnées).
- La valeur ne correspond pas à la plage attendue.
E.g. toute une série de types d'erreurs que nous ne pouvions pas simplement résoudre ou reproduire. Le 'Stack Empty' est celui qui se produit le plus, plusieurs centaines par jour (par exemple pour 1-10% des utilisateurs), donc nous nous concentrons sur celui-ci, car les autres erreurs semblent liées. Voici une trace de la pile partielle:
Exception information:
Exception type: System.InvalidOperationException
Exception message: Stack empty.
...
Stack trace: at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
at System.Collections.Generic.Stack`1.Pop()
at System.Web.WebPages.TemplateStack.Pop(HttpContextBase httpContext)
Comme le montre la trace de pile sont le plus souvent situé complètement dans le framwork MVC (System.Web). Le seul endroit dans notre propre code qui se produisait régulièrement dans certaines traces de pile était dans les vues (fichiers .cshtml) de l'URL demandée puis dans un appel @ Html.RenderAction(). À ce jour, nous en avons refacturé beaucoup à des appels RenderPartial(). Cela a conduit à l'absence de plus de vues dans la trace de la pile, bien que certains RenderPartial maintenant donné également certains
La recherche de cette erreur indiquée concomitance/exécution parallèle est la cause. Cela correspond au fait que nous n'avons initialement pas pu reproduire l'erreur localement, mais cela s'est produit en production. Nous n'avons effectué aucun test de charge, mais nous avons maintenant réussi à reproduire l'erreur sur un système de développement local en démarrant un grand nombre d'applications/demandes simultanément. Cependant, dans notre code, rien n'est fait avec des instructions parallèles explicites.
Cela semble être lié au fait que la vue MVC n'est PAS sûre pour les threads. Cependant, il est difficile d'imaginer que personne d'autre n'aurait rencontré cela. Nous avons quelques milliers de visiteurs par jour, environ 30 utilisateurs actifs à tout moment. Malheureusement, ce nombre est en baisse en raison de la baisse du classement de Google (liée à ce problème).
Est-ce que quelqu'un connaît une solution/approche de ce problème?
Est-ce que vous transmettez en tant que modèle un objet potentiellement accessible par plusieurs threads? Comme un objet partagé? – vtortola
vtorola Pas vraiment! Wel tous les modèles s'étendent à partir de BaseModel qui a un objet de contexte db statique, Cependant, cela est stocké dans le HTTPContext (en utilisant une clé). Ceci est fait de sorte qu'il est utilisé sur une base «par demande» (il est paresseux chargé sur le premier accès). Les traces de pile ne pointent PAS sur ce code, elles sont seulement dans la logique de vue. De plus, j'ai déjà ajouté une instruction 'lock' sur le code qui initialise le DB Context, juste au cas où. Cela n'a pas semblé changer quoi que ce soit. Nous utilisons Entity Framework. – Bart
Woa qui semble effrayant: D Vous devez utiliser votre DbContext dans le cadre de votre contrôleur, générer les objets POCO souhaités à partir de la base de données, puis créer vos modèles de vue. Une vue devrait être thread safe, je n'ai jamais vu une erreur comme ça, donc je suggère de commencer à regarder ce DbContext partagée effrayant profondément. Peut-être que la trace de la pile ne pointe pas vers cet objet BaseModel, mais qu'une partie est certainement partagée entre plusieurs threads. – vtortola