Posso accedere allo stato della sessione da un HTTPModule?


85

Potrei davvero fare con l'aggiornamento delle variabili di sessione di un utente dal mio HTTPModule, ma da quello che posso vedere, non è possibile.

AGGIORNAMENTO: il mio codice è attualmente in esecuzione all'interno del OnBeginRequest ()gestore eventi.

AGGIORNAMENTO: seguendo i consigli ricevuti finora, ho provato ad aggiungerlo alla Init ()routine nel mio HTTPModule:

AddHandler context.PreRequestHandlerExecute, AddressOf OnPreRequestHandlerExecute

Ma nella mia OnPreRequestHandlerExecuteroutine, lo stato della sessione non è ancora disponibile!

Grazie e scusa se mi manca qualcosa!

Risposte:


83

Ho trovato questo nei forum 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; }
      }
   }
}

8
MS dovrebbe risolvere questo problema! ... se contrassegno un modulo come implementante IRequiresSessionState, non dovrei dover saltare attraverso un cerchio per ottenerlo ... (codice sexy in effetti)
BigBlondeViking

6
Bel codice. Pensavo di averne bisogno, ma non è stato così. Questo codice finisce per caricare la sessione per ogni immagine e altra risorsa non di pagina che passa attraverso il server. Nel mio caso, controllo semplicemente se la sessione è nulla nell'evento PostAcquireRequestState e restituisco se lo è.
Abtin Forouzandeh

7
Questo codice è utile se la risorsa richiesta non gestisce lo stato della sessione. Per le pagine .aspx standard è sufficiente aggiungere il codice che accede alla sessione sul gestore di eventi PostAcquireRequestState. Lo stato della sessione non sarà disponibile su alcun gestore di eventi BeginRequest perché lo stato della sessione non è stato ancora acquisito.
JCallico

3
Non funziona nel mio caso. Ho ricevuto il messaggio "Lo stato della sessione non è disponibile in questo contesto". quando c'è una richiesta che tenta di accedere a un file statico. Qualsiasi aiuto ?
maxisam

3
Affinché funzioni sui file statici, devo, inoltre, registrare nuovamente il modulo della sessione (nel web.config) rimuovendo preCondition = "managedHandler" (<remove name = "Session" /> <add name = " Session "type =" System.Web.SessionState.SessionStateModule "/>)
nlips

39

HttpContext.Current.Session dovrebbe funzionare correttamente , supponendo che il modulo HTTP non stia gestendo alcun evento della pipeline che si verifica prima dell'inizializzazione dello stato della sessione ...

EDIT, dopo chiarimenti nei commenti: durante la gestione dell'evento BeginRequest , l'oggetto Session sarà infatti ancora null / Nothing, in quanto non è stato ancora inizializzato dal runtime ASP.NET. Per ovviare a questo, sposta il codice di gestione su un evento che si verifica dopo PostAcquireRequestState - Mi piace PreRequestHandlerExecute per questo, poiché tutto il lavoro di basso livello è praticamente svolto in questa fase, ma prevedi comunque qualsiasi normale elaborazione.


Purtroppo non è disponibile in HTTPModule - "Riferimento a un oggetto non impostato su un'istanza di un oggetto".
Chris Roberts,

Sto elaborando "OnBeginRequest"?
Chris Roberts,

Grazie per l'aggiornamento. Se lo gestisco in un evento a livello di applicazione, perché non eseguo tutta la mia elaborazione a livello di applicazione invece di utilizzare un HTTPModule?
Chris Roberts,

1
PostAcquireRequeststate non è un 'evento a livello di applicazione': se la richiesta HTTP è gestita da un gestore di servizi web, ad esempio, la vedrai ancora nel tuo modulo HTTP, ma non in Global.asax ...
mdb

Questo non sembra funzionare in modo affidabile per me. Il codice seguente causerà spesso un'eccezione "Lo stato della sessione non è disponibile in questo contesto". In effetti, blocca il debugger VS in modo abbastanza spettacolare. context.PreRequestHandlerExecute + = (sender, args) => Console.Write (((HttpApplication) sender) .Session ["test"];
cbp

15

Accesso a HttpContext.Current.Sessionin aIHttpModule può essere eseguito inPreRequestHandlerExecute gestore.

PreRequestHandlerExecute : "Si verifica appena prima che ASP.NET inizi l'esecuzione di un gestore eventi (ad esempio, una pagina o un servizio Web XML)." Ciò significa che prima che venga servita una pagina "aspx", questo evento viene eseguito. Lo 'stato della sessione' è disponibile così puoi metterti al tappeto.

Esempio:

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();
        }
...
}

Ho provato questo e ottieni davvero la sessione. Ma sembra che RequestHeader non sia completamente presente, in particolare HeaderContentType
Matthias Müller

12

Se stai scrivendo un normale HttpModule di base in un'applicazione gestita che desideri applicare alle richieste asp.net tramite pagine o gestori, devi solo assicurarti di utilizzare un evento nel ciclo di vita dopo la creazione della sessione. PreRequestHandlerExecute invece di Begin_Request è di solito dove vado. mdb ha ragione nella sua modifica.

Lo snippet di codice più lungo originariamente indicato come risposta alla domanda funziona, ma è complicato e più ampio della domanda iniziale. Gestirà il caso in cui il contenuto proviene da qualcosa che non dispone di un gestore ASP.net disponibile in cui è possibile implementare l'interfaccia IRequiresSessionState, attivando così il meccanismo di sessione per renderlo disponibile. (Come un file gif statico su disco). Fondamentalmente sta impostando un gestore fittizio che implementa semplicemente quell'interfaccia per rendere disponibile la sessione.

Se vuoi solo la sessione per il tuo codice, scegli semplicemente l'evento giusto da gestire nel tuo modulo.


0

Provalo: nella classe MyHttpModule dichiara:

private HttpApplication contextapp;

Poi:

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

E così, in un altro metodo (l'evento) nella stessa 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");
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.