Czy mogę uzyskać dostęp do stanu sesji z modułu HTTPModule?

85

Naprawdę przydałaby mi się aktualizacja zmiennych sesji użytkownika z poziomu mojego modułu HTTPModule, ale z tego, co widzę, nie jest to możliwe.

AKTUALIZACJA: Mój kod jest obecnie uruchomiony w programie OnBeginRequest ()obsługi zdarzeń.

AKTUALIZACJA: Zgodnie z otrzymanymi dotychczas poradami próbowałem dodać to do Init ()procedury w moim module HTTPModule:

AddHandler context.PreRequestHandlerExecute, AddressOf OnPreRequestHandlerExecute

Ale w mojej OnPreRequestHandlerExecuterutynie stan sesji jest nadal niedostępny!

Dzięki i przepraszam, jeśli czegoś brakuje!

Chris Roberts
źródło

Odpowiedzi:

83

Znalazłem to na forach 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
źródło
8
MS powinien to naprawić! ... jeśli oznaczę moduł jako implementujący IRequiresSessionState, nie powinienem musieć przeskakiwać przez obręcz, aby go zdobyć ... (rzeczywiście seksowny kod)
BigBlondeViking
6
Niezły kod. Myślałem, że będę tego potrzebować, ale okazuje się, że nie. Ten kod kończy ładowanie sesji dla każdego obrazu i innych zasobów niebędących stronami, które przechodzą przez serwer. W moim przypadku po prostu sprawdzam, czy sesja ma wartość null w zdarzeniu PostAcquireRequestState i zwracam, jeśli tak jest.
Abtin Forouzandeh
7
Ten kod jest przydatny, jeśli żądany zasób nie obsługuje stanu sesji. W przypadku standardowych stron .aspx wystarczy dodać kod, który uzyskuje dostęp do sesji, w module obsługi zdarzeń PostAcquireRequestState. Stan sesji nie będzie dostępny w żadnym programie obsługi zdarzeń BeginRequest, ponieważ stan sesji nie został jeszcze uzyskany.
JCallico
3
W moim przypadku to nie działa. Otrzymałem informację „Stan sesji nie jest dostępny w tym kontekście”. gdy pojawia się żądanie próbujące uzyskać dostęp do pliku statycznego. Jakaś pomoc ?
maxisam
3
Aby to działało na plikach statycznych, muszę dodatkowo ponownie zarejestrować moduł sesji (w pliku web.config), usuwając preCondition = "managedHandler" (<remove name = "Session" /> <add name = " Session "type =" System.Web.SessionState.SessionStateModule "/>)
pomija
39

HttpContext.Current.Session powinien po prostu działać, zakładając, że moduł HTTP nie obsługuje żadnych zdarzeń potoku, które występują przed zainicjowaniem stanu sesji ...

EDYTUJ, po wyjaśnieniu w komentarzach: podczas obsługi zdarzenia BeginRequest obiekt Session rzeczywiście nadal będzie miał wartość null / Nothing, ponieważ nie został jeszcze zainicjowany przez środowisko uruchomieniowe ASP.NET. Aby obejść ten problem, przenieś kod obsługi do zdarzenia, które występuje po PostAcquireRequestState - osobiście lubię PreRequestHandlerExecute , ponieważ cała praca na niskim poziomie jest prawie wykonywana na tym etapie, ale nadal poprzedzasz normalne przetwarzanie.

mdb
źródło
Niestety nie jest to dostępne w module HTTPModule - „Odwołanie do obiektu nie jest ustawione na wystąpienie obiektu”.
Chris Roberts
Przetwarzam „OnBeginRequest”?
Chris Roberts
Dziękuję za aktualizację. Jeśli obsłużę to w zdarzeniu na poziomie aplikacji, dlaczego nie wykonam całego przetwarzania na poziomie aplikacji, zamiast używać modułu HTTPModule?
Chris Roberts
1
PostAcquireRequeststate nie jest `` zdarzeniem na poziomie aplikacji '': jeśli na przykład żądanie HTTP jest obsługiwane przez program obsługi usługi sieciowej, nadal będzie to widoczne w module HTTP, ale nie w Global.asax ...
mdb
Wydaje mi się, że to nie działa niezawodnie. Poniższy kod często powoduje wyjątek „Stan sesji nie jest dostępny w tym kontekście”. W rzeczywistości dość spektakularnie zawiesza debugger VS. context.PreRequestHandlerExecute + = (sender, args) => Console.Write (((HttpApplication) sender) .Session ["test"];
cbp
15

Dostęp do HttpContext.Current.Sessionw a IHttpModulemożna wykonać w programie PreRequestHandlerExecuteobsługi.

PreRequestHandlerExecute : „Występuje tuż przed rozpoczęciem wykonywania programu obsługi zdarzeń przez program ASP.NET (na przykład strony lub usługi sieci Web XML).” Oznacza to, że przed udostępnieniem strony „aspx” to zdarzenie zostanie wykonane. „Stan sesji” jest dostępny, więc możesz się znokautować.

Przykład:

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
źródło
Próbowałem tego i rzeczywiście otrzymujesz sesję. Ale wygląda na to, że RequestHeader nie jest tam w pełni, szczególnie HeaderContentType
Matthias Müller
12

Jeśli piszesz normalny, podstawowy moduł HttpModule w zarządzanej aplikacji, którą chcesz zastosować do żądań asp.net za pośrednictwem stron lub programów obsługi, wystarczy upewnić się, że używasz zdarzenia w cyklu życia po utworzeniu sesji. Zwykle wybieram PreRequestHandlerExecute zamiast Begin_Request. mdb ma to w swojej edycji.

Dłuższy fragment kodu pierwotnie wymieniony jako odpowiedź na pytanie działa, ale jest skomplikowany i szerszy niż początkowe pytanie. Będzie obsługiwał przypadek, gdy zawartość pochodzi z czegoś, co nie ma dostępnej procedury obsługi ASP.net, w której można zaimplementować interfejs IRequiresSessionState, uruchamiając w ten sposób mechanizm sesji, aby ją udostępnić. (Jak statyczny plik gif na dysku). Zasadniczo polega na ustawieniu fikcyjnej obsługi, która następnie implementuje ten interfejs, aby udostępnić sesję.

Jeśli potrzebujesz tylko sesji dla swojego kodu, po prostu wybierz odpowiednie zdarzenie do obsługi w swoim module.

Obrabować
źródło
0

Spróbuj: w klasie MyHttpModule zadeklaruj:

private HttpApplication contextapp;

Następnie:

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

I tak w innej metodzie (zdarzeniu) w tej samej klasie:

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");
    }
}
Test
źródło