在ashx和静态文件中使用Session
在ashx页面中如果想使用可读可写的Session,必须要实现一个接口“IRequiresSessionState”,在这个接口中没有定义任何方法,这样的接口被称为“标识接口”。
public interface IRequiresSessionState { }
在IIS中,对后台的页面请求都会经过管道。如果该请求指向的是物理文件,并且该请求没有被路由,那么会通过地址去获得一个匹配的继承自HttpHandler的对象,获得到的对象会被保存在HttpContext的Handler属性中,以供请求的后续步骤使用。
public IHttpHandler Handler { get { return _handler;} set { _handler = value; _requiresSessionStateFromHandler = false; _readOnlySessionStateFromHandler = false; InAspCompatMode = false; if (_handler != null) { if (_handler is IRequiresSessionState) { _requiresSessionStateFromHandler = true; } if (_handler is IReadOnlySessionState) { _readOnlySessionStateFromHandler = true; } Page page = _handler as Page; if (page != null && page.IsInAspCompatMode) { InAspCompatMode = true; } } } }
上面贴出的代码就是HttpContext的Handler属性的get和set访问器,可以看到在set访问器中,通过判断当前的Handler对象是否继承自标识接口而为HttpContext的两个字段赋值。在后面的附加Session状态的方法中就会使用HttpContext的一个属性RequiresSessionState。
internal bool RequiresSessionState { get { switch (SessionStateBehavior) { case SessionStateBehavior.Required: case SessionStateBehavior.ReadOnly: return true; case SessionStateBehavior.Disabled: return false; case SessionStateBehavior.Default: default: return _requiresSessionStateFromHandler; } } }
这个属性中默认情况下会使用上面提到的字段_requiresSessionStateFromHandler。
SessionStateBehavior这个属性表示的是会话状态是被禁用、读写、只读,可以通过HttpContext的SetSessionStateBehavior对该属性进行赋值。
如果遇到需要在静态文件中也使用session的情况,那么必须先将runAllManagedModulesForAllRequests属性设置true,再在管道事件中的AcquireRequestState事件之前,手动设置会话状态行为,最后再配置会话状态httpmodule。
1、配置文件,配置所有静态文件都走管道
<configuration> ... <system.webServer> <modules runAllManagedModulesForAllRequests="true"> <remove name="Session"/> <add name="Session" type="System.Web.SessionState.SessionStateModule"/> </modules> </system.webServer> ... </configuration>
2、管道事件,设置静态文件的会话状态行为 protected void Application_PostMapRequestHandler(object sender, EventArgs e) { var app = (HttpApplication)sender; if (是需要校验会话状态的静态文件) { app.Context.SetSessionStateBehavior(SessionStateBehavior.Required); } }
3、配置文件,配置会话状态的module为SessionStateModule,这样就会使用到上面设置到SessionStateBehavior.Required
<configuration> <system.webServer> <modules runAllManagedModulesForAllRequests="true"> <remove name="Session"/> <add name="Session" type="System.Web.SessionState.SessionStateModule"/> </modules> </system.webServer> </configuration>