Могу ли я получить доступ к состоянию сеанса из 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
MS должна это исправить! ... если я помечу модуль как реализующий IRequiresSessionState, мне не придется прыгать через обруч, чтобы получить его ... (действительно сексуальный код)
BigBlondeViking
6
Хороший код. Я думал, мне это понадобится, но оказалось, что нет. Этот код завершает загрузку сеанса для каждого изображения и других ресурсов, не относящихся к странице, которые проходят через сервер. В моем случае я просто проверяю, является ли сеанс нулевым в событии PostAcquireRequestState, и возвращаю, если это так.
Abtin Forouzandeh
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-модуль не обрабатывает какие-либо события конвейера, которые происходят до инициализации состояния сеанса ...

ИЗМЕНИТЬ, после пояснения в комментариях: при обработке события BeginRequest объект Session действительно будет иметь значение null / Nothing, поскольку он еще не был инициализирован средой выполнения ASP.NET. Чтобы обойти это, переместите свой код обработки в событие, которое происходит после PostAcquireRequestState - мне лично нравится PreRequestHandlerExecute , так как вся низкоуровневая работа в значительной степени выполняется на этом этапе, но вы все равно предотвращаете любую нормальную обработку.

mdb
источник
К сожалению, это недоступно в 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");
    }
}
тест
источник