Question

Récemment, tout en travaillant sur du code pour un projet ASP.NET au travail. Nous avions besoin d’un utilitaire de suivi pour prendre des mesures de base sur l’activité des utilisateurs (nombre de visites de page, etc.). Nous les suivrions dans Session , puis enregistrez les données dans la base de données via Session_End dans Global.asax .

J'ai commencé à pirater, le code initial a bien fonctionné, mettant à jour la base de données à chaque chargement de page. Je souhaitais toutefois supprimer ce hit de base de données à chaque demande et me fier simplement à Session_End pour stocker toutes les données.

Tout le code de suivi est encapsulé dans la classe Tracker , y compris les propriétés qui enveloppent essentiellement les variables de session.

Le problème est que, lorsque j'ai exécuté Tracker.Log () dans la méthode Session_End , le HttpContext.Current.Session dans le code du Tracker était échec avec une NullReferenceException . Cela a du sens depuis HttpContext . / a> correspond toujours à la requête actuelle et, bien sûr, dans Session_End , il n'y a pas de requête.

Je sais que Global.asax a une propriété Session qui renvoie un HttpSessionState qui semble fonctionner correctement (j'ai fini par l'injecter). dans le tracker) ..

Mais je suis curieux de savoir comment puis-je obtenir la même référence à l'objet HttpSessionState utilisé par Global.asax à partir de l'extérieur de Global.asax ?

Merci d'avance les gars, j'apprécie votre contribution. :)

Était-ce utile?

La solution

Global.asax implémente HttpApplication - c'est ce à quoi vous parlez lorsque vous appelez this à l'intérieur de celui-ci.

La documentation MSDN relative à HttpApplication contient des informations détaillées sur comment vous pouvez l'obtenir dans un HttpHandler par exemple, puis accéder aux différentes propriétés qu'il contient.

TOUTEFOIS

Votre application peut créer plusieurs instances de HttpApplication pour gérer les demandes parallèles. Ces instances peuvent être réutilisées. Par conséquent, le simple fait de le récupérer ne garantit pas que vous en avez la bonne.

J'ajouterais aussi une mise en garde: si votre application se bloque, rien ne garantit que session_end sera appelée, et vous aurez perdu toutes les données de toutes les sessions, ce qui n'est clairement pas une bonne chose.

Je suis d'accord pour dire que la journalisation sur chaque page n'est probablement pas une bonne idée, mais peut-être une maison de transition avec une journalisation asynchrone en cours - vous envoyez des détails à une classe de journalisation, qui enregistre de temps en temps les détails que vous recherchez - encore pas solide à 100% si l'application se bloque, mais vous êtes moins susceptible de tout perdre.

Autres conseils

Pour mieux répondre à la question initiale:

Arrière-plan

Chaque demande de page unique génère un nouvel objet Session , puis le gonfle à partir de votre magasin de sessions. Pour ce faire, il utilise le cookie fourni par le client ou une construction de chemin d'accès spéciale (pour les sessions sans cookie). Avec cet identifiant de session, il consulte le magasin de session et désérialise (c'est pourquoi tous les fournisseurs sauf InProc doivent être sérialisables) du nouvel objet de session.

Dans le cas du fournisseur InProc, il vous remet simplement la référence stockée dans le HttpCache associé à l'identificateur de session. C’est pourquoi le fournisseur InProc supprime l’état de la session lorsque le AppDomain est recyclé (et également pourquoi plusieurs serveurs Web ne peuvent pas partager l’état de la session InProc .

Cet objet nouvellement créé et gonflé est bloqué dans la collection Context.Items , de sorte qu'il est disponible pour la durée de la demande.

Toutes les modifications que vous apportez à l'objet Session sont ensuite conservées à la fin de la demande au magasin de session par sérialisation (ou dans le cas d'InProc, l'entrée HttpCache est mis à jour).

Etant donné que Session_End est déclenché sans demande en cours, l'objet Session est créé ex-nilo, aucune information n'est disponible. Si vous utilisez l'état de session InProc, l'expiration de HttpCache déclenche un événement de rappel dans votre événement Session_End , de sorte que l'entrée de session est disponible, mais reste une copie de la dernière stocké dans le HttpContext.Cache . Cette valeur est stockée dans la propriété HttpApplication.Session par une méthode interne (appelée ProcessSpecialRequest ) où elle est ensuite disponible. Dans tous les autres cas, il provient en interne de la valeur HttpContext.Current.Session .

Votre réponse

Etant donné que Session_End se déclenche toujours avec un contexte nul, vous devez TOUJOURS utiliser this.Session dans cet événement et transmettre l'objet HttpSessionState à votre code de traçage. Dans tous les autres contextes, il est parfaitement approprié d'extraire de HttpContext.Current.Session , puis de le transférer dans le code de traçage. NE PAS , toutefois, laissez le code de suivi accéder au contexte de la session.

Ma réponse

N'utilisez pas Session_End sauf si vous savez que le magasin de session que vous utilisez prend en charge Session_End , ce qu'il utilise s'il renvoie true à partir de SetItemExpireCallback . Le seul magasin dans la boîte qui existe est le magasin InProcSessionState . Il est possible d'écrire un magasin de session qui le fait, mais la question de savoir qui va traiter le Session_End est un peu ambiguë s'il existe plusieurs serveurs.

Je pense que vous avez déjà répondu à votre propre question: généralement, la propriété Session dans Global.asax et HttpContext.Current.Session sont identiques (s'il existe une demande en cours). Mais dans le cas d’un délai de session, il n’ya pas de requête active et vous ne pouvez donc pas utiliser HttpContext.Current.

Si vous souhaitez accéder à la session à partir de la méthode appelée par Session_End, transmettez-la en tant que paramètre. Créez une version surchargée de la méthode Log (), qui prend un paramètre HttpSessionState, puis appelez Tracker.Log (this.Session) à partir du gestionnaire d'événements Session_End.

BTW: vous êtes conscient que vous ne pouvez en aucun cas compter sur l'événement de fin de session? Cela ne fonctionnera que tant que l'état de la session est en cours de traitement. Lors de l'utilisation de SQL Server ou StateServer pour gérer l'état de session, l'événement de fin de session ne se déclenchera pas.

L'événement Session_End est déclenché uniquement lorsque le mode Sessionstate est défini sur InProc dans Web.config . fichier. Si le mode de session est défini sur StateServer ou SQLServer , l'événement n'est pas déclenché.

utilisez Session [" SessionItemKey "]] pour obtenir la valeur de la session.

D'accord, je suis dans le même problème pour suivre l'activité de la session. Au lieu d'utiliser l'événement session_end, j'ai implémenté l'interface IDisposable et le destructeur de ma classe sessiontracker. J'ai modifié la méthode Dispose () pour enregistrer l'activité de session dans une base de données. J'ai appelé la méthode obj.Dispose () lorsqu'un utilisateur clique sur le bouton de déconnexion. Si l'utilisateur a fermé le navigateur par erreur, alors GC appellera le destructeur lors du nettoyage des objets (pas immédiatement mais avec certitude, il appellera cette méthode après un certain temps). La méthode destructor exécute en interne la même méthode Dispose () pour enregistrer les activités de session dans la base de données.

-Shan

La session est disponible dans votre fichier Global.asax lors de l'événement Session_Start. Peut-être attendre ce point pour faire des choses?

N'oubliez pas que Session_End s'exécute lorsque la session expire sans activité. Le navigateur n'étant pas à l'origine de cet événement (car il est inactif), le seul moment où vous obtiendrez l'événement est lors de l'utilisation du fournisseur InProc. Dans TOUS LES AUTRES fournisseurs, cet événement ne sera jamais déclenché.

Moral? N'utilisez pas Session_End.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top