¿Puedo acceder al estado de la sesión desde un HTTPModule?

85

Realmente podría actualizar las variables de sesión de un usuario desde mi HTTPModule, pero por lo que puedo ver, no es posible.

ACTUALIZACIÓN: Mi código se está ejecutando actualmente dentro del OnBeginRequest ()controlador de eventos.

ACTUALIZACIÓN: Siguiendo los consejos recibidos hasta ahora, intenté agregar esto a la Init ()rutina en mi HTTPModule:

AddHandler context.PreRequestHandlerExecute, AddressOf OnPreRequestHandlerExecute

¡Pero en mi OnPreRequestHandlerExecuterutina, el estado de la sesión aún no está disponible!

Gracias y disculpas si me falta algo.

Chris Roberts
fuente

Respuestas:

83

Encontré esto en los foros de 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
fuente
8
¡MS debería arreglar esto! ... si marco un módulo como implementando el IRequiresSessionState, no debería tener que saltar por un aro para obtenerlo ... (código sexy de hecho)
BigBlondeViking
6
Buen código. Pensé que necesitaría esto, pero resulta que no. Este código termina cargando la sesión para cada imagen y otro recurso que no es de página que pasa por el servidor. En mi caso, simplemente verifico si la sesión es nula en el evento PostAcquireRequestState y regreso si lo es.
Abtin Forouzandeh
7
Este código es útil si el recurso solicitado no maneja el estado de la sesión. Para las páginas .aspx estándar, simplemente agregue su código para acceder a la sesión en el controlador de eventos PostAcquireRequestState. El estado de la sesión no estará disponible en ningún controlador de eventos BeginRequest porque aún no se ha adquirido el estado de la sesión.
JCallico
3
En mi caso no funciona. Obtuve "El estado de la sesión no está disponible en este contexto". cuando hay una solicitud que intenta acceder a un archivo estático. Alguna ayuda ?
maxisam
3
Para que esto funcione en archivos estáticos, además, tengo que volver a registrar el módulo de sesión (en web.config) eliminando preCondition = "managedHandler" (<remove name = "Session" /> <add name = " Sesión "type =" System.Web.SessionState.SessionStateModule "/>)
nlips
39

HttpContext.Current.Session debería funcionar, asumiendo que su módulo HTTP no está manejando ningún evento de canalización que ocurra antes de que se inicialice el estado de la sesión ...

EDITAR, después de una aclaración en los comentarios: al manejar el evento BeginRequest , el objeto Session seguirá siendo nulo / Nada, ya que aún no ha sido inicializado por el tiempo de ejecución de ASP.NET. Para solucionar esto, mueva su código de manejo a un evento que ocurra después de PostAcquireRequestState ; me gusta PreRequestHandlerExecute para eso yo mismo, ya que todo el trabajo de bajo nivel está prácticamente hecho en esta etapa, pero aún se adelanta a cualquier procesamiento normal.

mdb
fuente
Desafortunadamente, eso no está disponible en HTTPModule: "Referencia de objeto no configurada para una instancia de un objeto".
Chris Roberts
Estoy procesando 'OnBeginRequest'?
Chris Roberts
Gracias por la actualización. Si lo manejo en un evento de nivel de aplicación, ¿por qué no hago todo mi procesamiento a nivel de aplicación en lugar de utilizar un módulo HTTP?
Chris Roberts
1
PostAcquireRequeststate no es un 'evento de nivel de aplicación': si la solicitud HTTP es manejada por un controlador de servicio web, por ejemplo, todavía la verá en su módulo HTTP, pero no en Global.asax ...
mdb
Esto no parece funcionar de manera confiable para mí. El siguiente código a menudo provocará una excepción "El estado de sesión no está disponible en este contexto". De hecho, bloquea el depurador VS de manera espectacular. context.PreRequestHandlerExecute + = (sender, args) => Console.Write (((HttpApplication) sender) .Session ["test"];
cbp
15

El acceso a HttpContext.Current.Sessionen a IHttpModulese puede hacer en elPreRequestHandlerExecute controlador.

PreRequestHandlerExecute : "Ocurre justo antes de que ASP.NET comience a ejecutar un controlador de eventos (por ejemplo, una página o un servicio Web XML)". Esto significa que antes de que se sirva una página 'aspx', este evento se ejecuta. El 'estado de sesión' está disponible para que pueda dejarse inconsciente.

Ejemplo:

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
fuente
Probé esto y obtienes la sesión de hecho. Pero parece que RequestHeader no está completamente allí, especialmente el HeaderContentType
Matthias Müller
12

Si está escribiendo un HttpModule normal y básico en una aplicación administrada que desea aplicar a las solicitudes de asp.net a través de páginas o controladores, solo debe asegurarse de que está utilizando un evento en el ciclo de vida después de la creación de la sesión. PreRequestHandlerExecute en lugar de Begin_Request es normalmente donde voy. mdb lo tiene bien en su edición.

El fragmento de código más largo que se enumeró originalmente como respuesta a la pregunta funciona, pero es complicado y más amplio que la pregunta inicial. Manejará el caso cuando el contenido provenga de algo que no tiene un controlador ASP.net disponible donde puede implementar la interfaz IRequiresSessionState, activando así el mecanismo de sesión para que esté disponible. (Como un archivo gif estático en disco). Básicamente se trata de configurar un controlador ficticio que luego simplemente implementa esa interfaz para que la sesión esté disponible.

Si solo desea la sesión para su código, simplemente elija el evento correcto para manejar en su módulo.

Robar
fuente
0

Pruébelo: en la clase MyHttpModule declare:

private HttpApplication contextapp;

Entonces:

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

Y así, en otro método (el evento) en la misma clase:

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");
    }
}
una prueba
fuente