Posso acessar o estado da sessão de um HTTPModule?

85

Eu realmente gostaria de atualizar as variáveis ​​de sessão de um usuário de dentro do meu HTTPModule, mas pelo que posso ver, não é possível.

ATUALIZAÇÃO: Meu código está em execução no OnBeginRequest ()manipulador de eventos.

ATUALIZAÇÃO: Seguindo os conselhos recebidos até agora, tentei adicionar isso à Init ()rotina em meu HTTPModule:

AddHandler context.PreRequestHandlerExecute, AddressOf OnPreRequestHandlerExecute

Mas na minha OnPreRequestHandlerExecuterotina, o estado da sessão ainda está indisponível!

Obrigado e desculpas se estou faltando alguma coisa!

Chris Roberts
fonte

Respostas:

83

Encontrei isso nos fóruns 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
fonte
8
MS deve consertar isso! ... se eu marcar um Módulo como implementando o IRequiresSessionState, eu não deveria ter que pular um aro para obtê-lo ... (código sexy de fato)
BigBlondeViking
6
Belo código. Achei que precisaria disso, mas descobri que não. Esse código acaba carregando a sessão para cada imagem e outro recurso que não seja da página que passa pelo servidor. No meu caso, eu simplesmente verifico se a sessão é nula no evento PostAcquireRequestState e retorno se for.
Abtin Forouzandeh
7
Este código é útil se o recurso solicitado não controla o estado da sessão. Para páginas .aspx padrão, basta adicionar seu código acessando a sessão no manipulador de eventos PostAcquireRequestState. O estado da sessão não estará disponível em nenhum manipulador de eventos BeginRequest porque o estado da sessão ainda não foi adquirido.
JCallico
3
Não funciona no meu caso. Recebi "O estado da sessão não está disponível neste contexto." quando há uma solicitação de acesso a um arquivo estático. Qualquer ajuda ?
maxisam
3
Para que isso funcione em arquivos estáticos, eu tenho, além disso, registrar novamente o módulo de sessão (no web.config) removendo o preCondition = "managedHandler" (<remove name = "Session" /> <add name = " Sessão "type =" System.Web.SessionState.SessionStateModule "/>)
nlips
39

HttpContext.Current.Session deve apenas funcionar, supondo que seu Módulo HTTP não esteja lidando com nenhum evento de pipeline que ocorra antes do estado da sessão ser inicializado ...

EDIT, após esclarecimento nos comentários: ao manipular o evento BeginRequest , o objeto Session ainda será null / Nothing, pois ainda não foi inicializado pelo runtime do ASP.NET. Para contornar isso, mova seu código de tratamento para um evento que ocorre após PostAcquireRequestState - eu mesmo gosto de PreRequestHandlerExecute para isso, pois todo o trabalho de baixo nível é praticamente concluído neste estágio, mas você ainda impede qualquer processamento normal.

mdb
fonte
Infelizmente, isso não está disponível no HTTPModule - "Referência de objeto não definida para uma instância de um objeto."
Chris Roberts
Estou processando 'OnBeginRequest'?
Chris Roberts
Obrigado pela atualização. Se eu manuseio isso em um evento de nível de aplicativo, por que não faço apenas todo o meu processamento no nível de aplicativo em vez de usar um módulo HTTP?
Chris Roberts
1
PostAcquireRequeststate não é um 'evento de nível de aplicativo': se a solicitação HTTP for tratada por um manipulador de serviço da web, por exemplo, você ainda a verá em seu módulo HTTP, mas não em Global.asax ...
mdb
Isso não parece funcionar de maneira confiável para mim. O código a seguir geralmente causa uma exceção 'O estado da sessão não está disponível neste contexto'. Na verdade, ele trava o depurador VS de forma espetacular. context.PreRequestHandlerExecute + = (sender, args) => Console.Write (((HttpApplication) sender) .Session ["test"];
cbp
15

O acesso ao HttpContext.Current.Sessionem a IHttpModulepode ser feito no PreRequestHandlerExecutemanipulador.

PreRequestHandlerExecute : "Ocorre pouco antes do ASP.NET começar a executar um manipulador de eventos (por exemplo, uma página ou um serviço da Web em XML)." Isso significa que antes de uma página 'aspx' ser exibida, esse evento é executado. O 'estado da sessão' está disponível para que você possa se surpreender.

Exemplo:

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
fonte
Eu tentei isso e você conseguiu a Sessão de fato. Mas parece que o RequestHeader não está totalmente lá, especialmente o HeaderContentType
Matthias Müller
12

Se você estiver escrevendo um HttpModule normal e básico em um aplicativo gerenciado que deseja aplicar às solicitações asp.net por meio de páginas ou manipuladores, você apenas precisa ter certeza de que está usando um evento no ciclo de vida após a criação da sessão. PreRequestHandlerExecute em vez de Begin_Request é geralmente onde eu vou. mdb tem direito em sua edição.

O trecho de código mais longo listado originalmente como resposta à pergunta funciona, mas é complicado e mais amplo do que a pergunta inicial. Ele tratará do caso em que o conteúdo está vindo de algo que não tem um manipulador ASP.net disponível onde você pode implementar a interface IRequiresSessionState, acionando assim o mecanismo de sessão para torná-lo disponível. (Como um arquivo gif estático no disco). Basicamente, é definir um manipulador fictício que apenas implementa essa interface para disponibilizar a sessão.

Se você deseja apenas a sessão para seu código, basta escolher o evento certo para manipular em seu módulo.

Roubar
fonte
0

Experimente: na classe MyHttpModule declare:

private HttpApplication contextapp;

Então:

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

E assim, em outro método (o evento) na mesma 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");
    }
}
um teste
fonte