在IHttpModule中会话不可用

4

在我的程序中,我试图在IHttpModule中使用会话变量。以下是我的代码。在VS 2010开发服务器中,这可以正常工作。但是当我尝试在IIS7中调试时,它显示异常System.Web.HttpException: Session state is not available in this context

那么为什么会话在开发服务器上可用,但在IIS 7上不可用呢?

using System;
using System.Web;

public class Globalizer : IHttpModule
{    
  public void Init(HttpApplication context)
  {
    context.AcquireRequestState += new EventHandler(setLanguage);
  }

  public void Dispose(){}

  public void setLanguage(Object sender, EventArgs i_eventArgs)
  {
    HttpApplication http_application = sender as HttpApplication;     
    http_application.Session["language"] = "test";

  }
}
4个回答

1
你只需要实现IRequiresSessionState即可。
所以你的代码应该是这样的:
public class Globalizer : IHttpModule, IRequiresSessionState

如果你只是读取Sessions(从不更新它们),那么你应该使用IReadOnlySessionState,因为它不会锁定会话状态,因此你不会遇到并发请求的情况。

balexandre:我认为Ravi的答案是你答案的实现。这是实现IRequiresSessionState的正确方式吗? - Nayana Adassuriya

0
在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'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; }
      }
   }
}

Ravi:不太幸运,实际上我之前尝试过这个。同样的异常System.Web.HttpException: Session state is not available in this context. - Nayana Adassuriya

0

找到了原因。

是因为AcquireRequestState会触发所有文件的请求,例如CSS、JS和图片。这些文件没有会话。

解决方案:似乎有一种方法可以避免为所有请求调用IHttpModule。请查看此答案JS、Images和CSS被HTTPModule拦截

但对我来说没有用。所以我使用了HttpContext.Current.Session而不是HttpApplication.Session,每次在保存到会话之前都检查会话是否为空。

如果有人知道如何避免为除.aspx之外的文件调用IHttpModule,请在此处提供帮助。

以下是最终代码:

using System;
using System.Web;

public class Globalizer : IHttpModule
{    
  public void Init(HttpApplication context)
  {
    context.AcquireRequestState += new EventHandler(setLanguage);
  }

  public void Dispose(){}

  public void setLanguage(Object sender, EventArgs i_eventArgs)
  {
    if(HttpContext.Current.Session != null){
      HttpContext.Current.Session["language"] = "test";
    }

  }
}

编辑:另一种方法是仅在请求到达.aspx文件时使用会话。

HttpApplication http_application = sender as HttpApplication; 
HttpContext context = http_application.Context;
if(Path.GetExtension(context.Request.PhysicalPath) == ".aspx")
{
 HttpContext.Current.Session["language"] = "test";
 http_application.Session["language2"] = "test2";
} 

0
如果可能的话,将您的处理程序移动到PostAcquireRequestState处理程序中:

当与当前请求相关联的请求状态(例如会话状态)已获取时发生。

(或更晚的事件)

SessionStateModule本身响应AcquireRequestState事件加载会话状态 - 因此,目前您取决于您的模块或会话状态模块的处理程序先触发哪个。


Damien_The_Unbeliever- 谢谢你的建议。但是它不起作用。同样的异常。我在想我的程序在开发服务器上是如何工作的? - Nayana Adassuriya

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接