Могу ли я получить доступ к состоянию сеанса из HTTPModule?

Я мог бы действительно делать с обновлением переменных сеанса пользователя из моего HTTPModule, но из того, что я вижу, это невозможно.

UPDATE: мой код в настоящее время запущен внутри обработчика событий OnBeginRequest ().

UPDATE: после получения рекомендаций, полученных до сих пор, я попытался добавить это к подпрограмме Init () в моем HTTPModule:

AddHandler context.PreRequestHandlerExecute, AddressOf OnPreRequestHandlerExecute

Но в моей подпрограмме OnPreRequestHandlerExecute состояние сеанса по-прежнему недоступно!

Спасибо, и извиняюсь, если я что-то упустил!

Ответ 1

Обнаружено это на форумах 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,
// regradless 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 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; }
      }
   }
}

Ответ 2

HttpContext.Current.Session должен просто работать, если ваш HTTP-модуль не обрабатывает события конвейера, которые происходят до инициализации состояния сеанса...

EDIT, после пояснения в комментариях: при обработке BeginRequest event объект Session действительно будет иметь значение null/Nothing, поскольку он hasn ' t был инициализирован временем выполнения ASP.NET. Чтобы обойти это, переместите код обработки в событие, которое происходит после PostAcquireRequestState - мне нравится PreRequestHandlerExecute для себя, так как все низкоуровневые работы в значительной степени выполняются на этом этапе, но вы все еще претерпеваете любую нормальную обработку.

Ответ 3

Доступ к HttpContext.Current.Session в 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();
        }
...
}

Ответ 4

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

Более длинный фрагмент кода, первоначально указанный в ответе на вопрос, работает, но сложнее и шире, чем исходный вопрос. Он будет обрабатывать случай, когда контент поступает из того, что не имеет обработчика ASP.net, где вы можете реализовать интерфейс IRequiresSessionState, тем самым инициируя механизм сеанса, чтобы сделать его доступным. (Как статический файл gif на диске). Он в основном устанавливает фиктивный обработчик, который затем просто реализует этот интерфейс, чтобы сделать сеанс доступным.

Если вам просто нужен сеанс для вашего кода, просто выберите подходящее событие для обработки в вашем модуле.

Ответ 5

Попробуйте: в классе 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");
    }
}