Чи можу я отримати доступ до стану сеансу з HTTPModule?


85

Я дійсно міг би зробити з оновленням змінних сеансу користувача з мого HTTPModule, але з того, що я бачу, це не можливо.

ОНОВЛЕННЯ: Мій код зараз працює в OnBeginRequest ()обробнику подій.

ОНОВЛЕННЯ: Отримавши досі пораду, я спробував додати це до Init ()процедури в моєму HTTPModule:

AddHandler context.PreRequestHandlerExecute, AddressOf OnPreRequestHandlerExecute

Але в моїй OnPreRequestHandlerExecuteрутині стан сеансу все ще недоступний!

Дякую, і вибачаюся, якщо чогось мені не вистачає!

Відповіді:


83

Знайшов це на форумах 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
Державі-члену слід це виправити! ... якщо я позначу модуль як реалізацію IRequiresSessionState, мені не доведеться стрибати через обруч, щоб його отримати ... (справді сексуальний код)
BigBlondeViking

6
Хороший код. Я думав, що мені це знадобиться, але виявляється, ні. Цей код закінчується завантаженням сеансу для кожного зображення та інших несторінкових ресурсів, які проходять через сервер. У моєму випадку я просто перевіряю, чи є сесія нульовим у події PostAcquireRequestState, і повертаю, якщо вона є.
Абтін Форузанде

7
Цей код корисний, якщо запитуваний ресурс не обробляє стан сеансу. Для стандартних сторінок .aspx просто додайте код, який отримує доступ до сеансу, у обробнику подій PostAcquireRequestState. Стан сеансу не буде доступний для будь-якого обробника події BeginRequest, оскільки стан сеансу ще не отримано.
JCallico

3
У моєму випадку це не працює. Я отримав "Стан сесії недоступний у цьому контексті". коли є запит, який намагається отримати доступ до статичного файлу. Будь-яка допомога?
maxisam

3
Щоб це працювало над статичними файлами, я, крім того, перереєстрував модуль сеансу (у web.config), видаливши preCondition = "managedHandler" (<remove name = "Session" /> <add name = " Session "type =" System.Web.SessionState.SessionStateModule "/>)
nlips

39

HttpContext.Current.Session повинен просто працювати, припускаючи, що ваш модуль HTTP не обробляє жодних конвеєрних подій, що відбуваються до ініціалізації стану сеансу ...

EDIT, після роз’яснень у коментарях: при обробці події BeginRequest об’єкт Session дійсно все ще буде нульовим / нічим, оскільки він ще не ініціалізований середовищем виконання ASP.NET. Щоб обійти це, перемістіть ваш код обробки до події, яка відбувається після PostAcquireRequestState - мені це подобається PreRequestHandlerExecute , оскільки на цьому етапі вся робота на низькому рівні в основному виконана, але ви все одно попереджаєте будь-яку звичайну обробку.


На жаль, це недоступно в HTTPModule - "Посилання на об'єкт не встановлено як екземпляр об'єкта."
Кріс Робертс,

Я обробляю "OnBeginRequest"?
Кріс Робертс,

Дякуємо за оновлення. Якщо я обробляю це під час події на рівні програми, чому б мені просто не виконувати всю свою обробку на рівні програми, замість використання HTTPModule?
Кріс Робертс,

1
PostAcquireRequeststate не є "подією на рівні програми": якщо HTTP-запит обробляється обробником веб-служб, наприклад, ви все одно побачите його у своєму модулі HTTP, але не в Global.asax ...
mdb

Здається, це не працює надійно для мене. Наступний код часто спричиняє виняток "Стан сеансу недоступний у цьому контексті". Насправді він досить ефектно збиває налагоджувач VS. context.PreRequestHandlerExecute + = (sender, args) => Console.Write ((((HttpApplication) sender) .Session ["test"];
cbp

15

Доступ до файлу HttpContext.Current.Sessionin IHttpModuleможна зробити в PreRequestHandlerExecuteобробнику.

PreRequestHandlerExecute : "Відбувається безпосередньо перед тим, як ASP.NET починає виконувати обробник подій (наприклад, сторінку або веб-службу XML)." Це означає, що до подання сторінки "aspx" ця подія виконується. "Стан сесії" доступний, тому ви можете вибити себе.

Приклад:

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

Я спробував це, і ви справді отримуєте сесію. Але, схоже, RequestHeader ще не повністю, особливо HeaderContentType
Маттіас Мюллер

12

Якщо ви пишете звичайний базовий HttpModule в керованому додатку, який ви хочете застосувати до запитів asp.net через сторінки чи обробники, вам просто потрібно переконатися, що ви використовуєте подію в життєвому циклі після створення сеансу. Зазвичай я переходжу до PreRequestHandlerExecute замість Begin_Request. mdb має це прямо у своєму редагуванні.

Довший фрагмент коду, спочатку вказаний як відповідь на запитання, працює, але складний і ширший, ніж початкове запитання. Він буде обробляти випадок, коли вміст надходить з чогось, що не має обробника ASP.net, де ви можете реалізувати інтерфейс IRequiresSessionState, таким чином запускаючи механізм сеансу, щоб зробити його доступним. (Як статичний файл GIF на диску). В основному це встановлення фіктивного обробника, який потім просто реалізує цей інтерфейс, щоб зробити сеанс доступним.

Якщо вам просто потрібен сеанс для вашого коду, просто виберіть потрібну подію для обробки у вашому модулі.


0

Спробуйте: у класі MyHttpModule оголосіть:

private HttpApplication contextapp;

Тоді:

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

Отже, в іншому методі (події) в тому ж класі:

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");
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.