Puis-je accéder à l'état de session à partir d'un module HTTP?

85

Je pourrais vraiment faire avec la mise à jour des variables de session d'un utilisateur à partir de mon HTTPModule, mais d'après ce que je peux voir, ce n'est pas possible.

MISE À JOUR: Mon code s'exécute actuellement dans le OnBeginRequest ()gestionnaire d'événements.

MISE À JOUR: Suite aux conseils reçus jusqu'à présent, j'ai essayé d'ajouter ceci à la Init ()routine dans mon HTTPModule:

AddHandler context.PreRequestHandlerExecute, AddressOf OnPreRequestHandlerExecute

Mais dans ma OnPreRequestHandlerExecuteroutine, l'état de la session est toujours indisponible!

Merci et excuses si je manque quelque chose!

Chris Roberts
la source

Réponses:

83

J'ai trouvé ceci sur les forums ASP.NET :

using System;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;
using System.Diagnostics;

// This code demonstrates how to make session state available in HttpModule,
// regardless of requested resource.
// author: Tomasz Jastrzebski

public class MyHttpModule : IHttpModule
{
   public void Init(HttpApplication application)
   {
      application.PostAcquireRequestState += new EventHandler(Application_PostAcquireRequestState);
      application.PostMapRequestHandler += new EventHandler(Application_PostMapRequestHandler);
   }

   void Application_PostMapRequestHandler(object source, EventArgs e)
   {
      HttpApplication app = (HttpApplication)source;

      if (app.Context.Handler is IReadOnlySessionState || app.Context.Handler is IRequiresSessionState) {
         // no need to replace the current handler
         return;
      }

      // swap the current handler
      app.Context.Handler = new MyHttpHandler(app.Context.Handler);
   }

   void Application_PostAcquireRequestState(object source, EventArgs e)
   {
      HttpApplication app = (HttpApplication)source;

      MyHttpHandler resourceHttpHandler = HttpContext.Current.Handler as MyHttpHandler;

      if (resourceHttpHandler != null) {
         // set the original handler back
         HttpContext.Current.Handler = resourceHttpHandler.OriginalHandler;
      }

      // -> at this point session state should be available

      Debug.Assert(app.Session != null, "it did not work :(");
   }

   public void Dispose()
   {

   }

   // a temp handler used to force the SessionStateModule to load session state
   public class MyHttpHandler : IHttpHandler, IRequiresSessionState
   {
      internal readonly IHttpHandler OriginalHandler;

      public MyHttpHandler(IHttpHandler originalHandler)
      {
         OriginalHandler = originalHandler;
      }

      public void ProcessRequest(HttpContext context)
      {
         // do not worry, ProcessRequest() will not be called, but let's be safe
         throw new InvalidOperationException("MyHttpHandler cannot process requests.");
      }

      public bool IsReusable
      {
         // IsReusable must be set to false since class has a member!
         get { return false; }
      }
   }
}
Jim Harte
la source
8
MS devrait résoudre ce problème! ... si je marque un module comme implémentant l'IRequiresSessionState, je ne devrais pas avoir à sauter à travers un cerceau pour l'obtenir ... (code sexy en effet)
BigBlondeViking
6
Beau code. Je pensais que j'en aurais besoin, mais il s'avère que non. Ce code finit par charger la session pour chaque image et autre ressource non-page qui passe par le serveur. Dans mon cas, je vérifie simplement si la session est nulle dans l'événement PostAcquireRequestState et je retourne si c'est le cas.
Abtin Forouzandeh
7
Ce code est utile si la ressource demandée ne gère pas l'état de session. Pour les pages .aspx standard, ajoutez simplement votre code d'accès à la session sur le gestionnaire d'événements PostAcquireRequestState. L'état de session ne sera disponible sur aucun gestionnaire d'événements BeginRequest car l'état de session n'a pas encore été acquis.
JCallico
3
Cela ne fonctionne pas dans mon cas. J'ai "L'état de session n'est pas disponible dans ce contexte." lorsqu'une demande tente d'accéder à un fichier statique. De l'aide ?
maxisam
3
Pour que cela fonctionne sur des fichiers statiques, j'ai en outre réenregistré le module de session (dans le web.config) en supprimant le preCondition = "managedHandler" (<remove name = "Session" /> <add name = " Session "type =" System.Web.SessionState.SessionStateModule "/>)
nlips
39

HttpContext.Current.Session devrait simplement fonctionner, en supposant que votre module HTTP ne gère aucun événement de pipeline qui se produit avant l'initialisation de l'état de session ...

EDIT, après clarification dans les commentaires: lors de la gestion de l' événement BeginRequest , l'objet Session sera en effet toujours null / Nothing, car il n'a pas encore été initialisé par le runtime ASP.NET. Pour contourner ce problème , déplacez votre code de gestion vers un événement qui se produit après PostAcquireRequestState - j'aime PreRequestHandlerExecute pour cela moi-même, car tout le travail de bas niveau est pratiquement terminé à ce stade, mais vous anticipez toujours tout traitement normal.

mdb
la source
Malheureusement, ce n'est pas disponible dans HTTPModule - "La référence d'objet n'est pas définie sur une instance d'un objet."
Chris Roberts
Je traite "OnBeginRequest"?
Chris Roberts
Merci pour la mise à jour. Si je le gère dans un événement au niveau de l'application, pourquoi ne pas faire tout mon traitement au niveau de l'application au lieu d'utiliser un module HTTP?
Chris Roberts
1
PostAcquireRequeststate n'est pas un `` événement au niveau de l'application '': si la requête HTTP est gérée par un gestionnaire de service Web, par exemple, vous la verrez toujours dans votre module HTTP, mais pas dans Global.asax ...
mdb
Cela ne semble pas fonctionner de manière fiable pour moi. Le code suivant provoquera souvent une exception «L'état de session n'est pas disponible dans ce contexte». En fait, il plante le débogueur VS de manière assez spectaculaire. context.PreRequestHandlerExecute + = (expéditeur, args) => Console.Write (((HttpApplication) sender) .Session ["test"];
cbp
15

L'accès à HttpContext.Current.Sessiondans a IHttpModulepeut être effectué dans le PreRequestHandlerExecutegestionnaire.

PreRequestHandlerExecute : "Se produit juste avant qu'ASP.NET ne commence à exécuter un gestionnaire d'événements (par exemple, une page ou un service Web XML)." Cela signifie qu'avant qu'une page 'aspx' ne soit diffusée, cet événement est exécuté. L '«état de session» est disponible pour que vous puissiez vous assommer.

Exemple:

public class SessionModule : IHttpModule 
    {
        public void Init(HttpApplication context)
        {
            context.BeginRequest += BeginTransaction;
            context.EndRequest += CommitAndCloseSession;
            context.PreRequestHandlerExecute += PreRequestHandlerExecute;
        }



        public void Dispose() { }

        public void PreRequestHandlerExecute(object sender, EventArgs e)
        {
            var context = ((HttpApplication)sender).Context;
            context.Session["some_sesion"] = new SomeObject();
        }
...
}
Bert Persyn
la source
J'ai essayé ceci, et vous obtenez la session en effet. Mais il semble que le RequestHeader ne soit pas complètement là, en particulier le HeaderContentType
Matthias Müller
12

Si vous écrivez un HttpModule de base normal dans une application gérée que vous souhaitez appliquer aux requêtes asp.net via des pages ou des gestionnaires, vous devez simplement vous assurer que vous utilisez un événement dans le cycle de vie après la création de la session. PreRequestHandlerExecute au lieu de Begin_Request est généralement l'endroit où je vais. mdb l'a bien dans son édition.

L'extrait de code plus long répertorié à l'origine comme répondant à la question fonctionne, mais il est compliqué et plus large que la question initiale. Il gérera le cas où le contenu provient de quelque chose qui n'a pas de gestionnaire ASP.net disponible où vous pouvez implémenter l'interface IRequiresSessionState, déclenchant ainsi le mécanisme de session pour le rendre disponible. (Comme un fichier gif statique sur le disque). Il s'agit essentiellement de définir un gestionnaire factice qui implémente simplement cette interface pour rendre la session disponible.

Si vous voulez juste la session pour votre code, choisissez simplement le bon événement à gérer dans votre module.

Rob
la source
0

Essayez-le: dans la classe MyHttpModule déclarez:

private HttpApplication contextapp;

Ensuite:

public void Init(HttpApplication application)
{
     //Must be after AcquireRequestState - the session exist after RequestState
     application.PostAcquireRequestState += new EventHandler(MyNewEvent);
     this.contextapp=application;
}  

Et donc, dans une autre méthode (l'événement) dans la même classe:

public void MyNewEvent(object sender, EventArgs e)
{
    //A example...
    if(contextoapp.Context.Session != null)
    {
       this.contextapp.Context.Session.Timeout=30;
       System.Diagnostics.Debug.WriteLine("Timeout changed");
    }
}
un examen
la source