Contexte d'objet Entity Framework dans un objet de session ASP.NET?

asp.net entity-framework httpcontext objectcontext session

Question

Nous avons une application multicouches Asp.NET Web Forms. La couche de données a une classe appelée DataAccess qui implémente IDisposable et une instance de notre contexte d'objet Entity Framework en tant que champ privé. La classe a un certain nombre de méthodes publiques renvoyant diverses collections d'entités et disposera de son contexte d'objet lors de sa suppression.

En raison d'un certain nombre de problèmes auxquels nous avons été confrontés, nous avons décidé qu'il serait très avantageux de conserver le contexte d'objet (ou une instance de DataAccess ) plus longtemps sur le serveur. Il a été suggéré de conserver une instance dans la collection HttpContext.Current.Items de cette publication afin d’avoir une instance par requête Http.

Ce que je me demande, c'est: quels problèmes / préoccupations / problèmes découleraient du stockage d'une instance de notre contexte d'objet dans l'objet HttpContext.Current.Session ????

  • Je suppose que l'objet Session est finalisé et défini pour le garbage collection à l'expiration de la session d'un utilisateur. L'instance sera donc correctement supprimée.
  • Je suppose que la plupart des paramètres de navigateur par défaut laisseront notre application placer son cookie SessionId sans scrupule.
  • La quantité de données que le contexte d'objet traitera n'est pas énorme et ne posera pas de problème pour notre matériel serveur décent, en ce qui concerne la mise en cache au fil du temps et relativement peu d'utilisateurs concurrents.

Cela sera relativement rapide à mettre en œuvre et n'affectera pas nos nombreux tests unitaires existants.

Nous allons utiliser AutoFac et une classe ServiceProvider pour fournir des instances. Lorsqu'une instance de ObjectContext est requise, elle sera renvoyée par un code similaire à celui-ci:

private static Entities GetEntities(IContext context)
{
    if (HttpContext.Current == null)
    {
        return new Entities();
    }

    if (HttpContext.Current.Session[entitiesKeyString] == null)
    {
        HttpContext.Current.Session[entitiesKeyString] = new Entities();
    }

    return (Entities)HttpContext.Current.Session[entitiesKeyString];
}

À votre santé.

Réponse acceptée

Stocker un ObjectContext à l’état de session n’est pas une bonne pratique car la classe est destinée à encapsuler un modèle d’unité de travail - vous chargez des données (entités), vous les modifiez, vous engagez vos modifications (qui sont suivis par l’UOW), et vous en avez fini. Les objets UOW ne sont ni destinés ni conçus pour une longue durée de vie.

Cela dit, cela peut se faire sans causer de catastrophe majeure, il suffit de s’assurer de bien comprendre ce qui se passe dans les coulisses. Veuillez continuer à lire si vous envisagez de le faire afin de savoir dans quoi vous vous engagez et de connaître les compromis.


Je suppose que l'objet Session est finalisé et défini pour le garbage collection à l'expiration de la session d'un utilisateur. L'instance sera donc correctement supprimée.

Ceci est en fait inexact, ou du moins semble être basé sur la façon dont il est libellé. L'expiration / la déconnexion de la session n'entraînera pas la suppression immédiate de l'un des éléments. Ils seront éventuellement finalisés / éliminés, mais cela dépend du ramasse-miettes et vous n’avez aucun contrôle sur le moment où ils se produisent. Le plus gros problème potentiel ici est que si vous ouvrez manuellement une connexion sur ObjectContext , qui ne sera pas automatiquement fermée, vous ObjectContext perdre des connexions de base de données, ce qui ne serait pas découvert régulièrement. tests unitaires / tests d'intégration / tests en direct.

La quantité de données que le contexte d'objet traitera n'est pas énorme et ne posera pas de problème pour notre matériel serveur décent, en ce qui concerne la mise en cache au fil du temps et relativement peu d'utilisateurs concurrents.

Il suffit de garder à l’esprit que la croissance est sans bornes. Si un utilisateur particulier décide d'utiliser votre site pendant 12 heures consécutives, en exécutant des requêtes différentes toute la journée, le contexte ne fera que grandir. Un ObjectContext n'a pas sa propre "collecte de mémoire" interne, il ne nettoie pas les entités mises en cache / suivies qui n'ont pas été utilisées depuis longtemps. Si vous êtes certain que cela ne posera pas de problème en fonction de vos cas d'utilisation, c'est bien, mais le principal problème qui devrait vous préoccuper est le fait que vous ne maîtrisez pas la situation.


Un autre problème est la sécurité des threads. ObjectContext n'est pas thread-safe. L'accès à la session est normalement sérialisé, de sorte qu'une demande bloque l'attente de son état de session jusqu'à la fin d'une autre demande pour la même session. Toutefois, si quelqu'un décide de faire des optimisations plus tard, en particulier l'optimisation des sessions en lecture seule au niveau de la page, les demandes n'auront plus de verrou exclusif et il vous serait possible de vous retrouver avec différentes conditions de concurrence ou problèmes de ré-entrée. .

Le dernier mais non le moindre est bien sûr le problème de la simultanéité multi-utilisateurs. Un ObjectContext met en cache ses entités pour toujours et jusqu'à ce qu'il soit éliminé. Si un autre utilisateur modifie les mêmes entités sur son propre ObjectContext , le propriétaire du premier ObjectContext ne sera jamais informé de cette modification. Ces problèmes de données obsolètes peuvent être extrêmement difficiles à résoudre, car vous pouvez réellement voir la requête aller dans la base de données et revenir avec de nouvelles données, mais ObjectContext les écrasera avec les anciennes données obsolètes déjà stockées dans le cache. À mon avis, c'est probablement la raison la plus importante pour éviter les instances ObjectContext longue durée; même lorsque vous pensez que vous l'avez codé pour extraire les données les plus récentes de la base de données, ObjectContext décide qu'il est plus intelligent que vous et vous restitue les anciennes entités.


Si vous êtes au courant de tous ces problèmes et avez pris des mesures pour les atténuer, c'est bien. Mais ma question serait la suivante: pourquoi pensez-vous exactement qu'un objet ObjectContext niveau de la ObjectContext est une si bonne idée? La création d'un ObjectContext est une opération très économique, car les métadonnées sont mises en cache pour l'ensemble de l'AppDomain. Je parie que vous supposez soit que vous avez l’impression erronée que cela coûte cher, soit que vous essayez de mettre en œuvre des processus complexes avec état sur plusieurs pages Web différentes, et que les conséquences à long terme de cette dernière sont bien pires que celles spécifiées. vous pouvez faire du mal en mettant simplement un ObjectContext dans la session.

Si vous voulez le faire de toute façon, assurez-vous de le faire pour les bonnes raisons, car il n'y a pas beaucoup de bonnes raisons de le faire. Mais, comme je l'ai dit, c'est tout à fait possible, et votre application ne va pas exploser en conséquence.


Mise à jour - pour tous ceux qui envisagent de passer au vote inférieur parce que "plusieurs demandes sur la même session pourraient causer des problèmes de sécurité des threads", veuillez lire le bas de la documentation de présentation de l'état de session ASP.NET . Ce ne sont pas seulement les accès individuels de l'état de session qui sont sérialisés; toute demande qui acquiert une session conserve un verrou exclusif sur la session qui n'est pas libérée tant que la demande n'est pas complète. À l'exception de certaines des optimisations que j'ai énumérées ci-dessus, il est impossible dans la configuration par défaut de ne jamais avoir deux demandes simultanées contenant des références à la même instance de session locale d'un objet ObjectContext .

Je ne voudrais toujours pas stocker un ObjectContext à l'état de session pour plusieurs des raisons énumérées ci-dessus, mais ce n'est pas un problème de sécurité des threads, sauf si vous en faites un.


Réponse populaire

Vous devez utiliser un objet ObjectContext par requête, vous ne devriez pas le stocker en tant que session. Il est facile de détruire les données stockées dans ObjectContext pendant une longue période:

  1. Que faire si vous insérez des données qui ne violent pas les règles dans ObjectContext, mais violent les règles de la base de données? Si vous insérez une ligne qui ne respecte pas les règles, la supprimerez-vous du contexte? Situation de l'image: vous utilisez un contexte et vous demandez soudainement de modifier les données d'une table, d'ajouter une ligne à une autre table et d'appeler SaveChanges (). Une des modifications renvoie une erreur de violation de contrainte. Comment nettoyez-vous? Le contexte de nettoyage n’est pas facile, il est plus facile d’en obtenir un nouveau à la prochaine demande.

  2. Que se passe-t-il si quelqu'un supprime des données de la base de données alors qu'elles sont encore dans le contexte? ObjectContext met en cache les données et ne vérifie pas de temps en temps si elles sont toujours présentes ou si elles ont changé :)

  3. Et si quelqu'un change de web.config et que la session est perdue? Il semble que vous souhaitiez utiliser Session pour stocker des informations sur l'utilisateur connecté. Le cookie d'authentification par formulaire est un endroit plus fiable pour stocker ces informations. La session peut être perdue dans de nombreuses situations.

ObjectContext a été conçu pour être de courte durée, il est préférable de le créer à la demande si nécessaire et de le supprimer à la fin.

Si le contexte par requête ne fonctionne pas pour vous, vous faites probablement quelque chose de mal, mais n'empirez pas les choses en utilisant Session.



Related

Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow