Bra*_*d M 1 asp.net session outputcache iis-7.5
问题:当从缓存中提取请求的aspx页面时,为什么没有创建会话(和会话cookie)?
背景资料
我做了很多谷歌搜索,但我找不到任何表明这是预期的行为.我们期望的行为是始终生成新的会话/ cookie,无论所请求的页面是否从缓存中拉出.
我们使用以下代码缓存页面.(.NET 3.5,IIS 7.5)
Response.Cache.SetExpires(DateTime.Now.AddMonths(1));
Response.Cache.SetCacheability(HttpCacheability.Server);
Response.Cache.SetVaryByCustom("IsLoggedIn");
Response.Cache.VaryByParams["*"] = true;
Response.Cache.SetValidUntilExpires(true);
Response.AddCacheItemDependency("Pages");
Run Code Online (Sandbox Code Playgroud)
任何相关信息将不胜感激.
为了理解输出缓存请求不会创建会话的原因,您需要了解ASP.NET应用程序生命周期(事件).基础是在每个请求期间可能触发的一系列定义的HttpApplication
事件.这些事件通常由HttpModule实现或Global.asax文件使用事件处理程序订阅.
并非每个应用程序事件都会在每个请求中触发,但是触发的事件将始终以定义的顺序触发.在IIS 7上触发的事件的顺序
1. BeginRequest
2. AuthenticateRequest
PostAuthenticateRequest
3. AuthorizeRequest
PostAuthorizeRequest
4. ResolveRequestCache
PostResolveRequestCache
5. MapRequestHandler (Integrated Mode Only)
PostMapRequestHandler
6. AcquireRequestState
PostAcquireRequestState
7. PreRequestHandlerExecute
<--- the IHttpHandler.ProcessRequest() method is called here
PostRequestHandlerExecute
8. ReleaseRequestState
PostReleaseRequestState
9. UpdateRequestCache
PostUpdateRequestCache
10. LogRequest (Integrated Mode Only)
PostLogRequest (Integrated Mode Only)
11. EndRequest
12. PreSendRequestHeaders
13. PreSendRequestContent
Run Code Online (Sandbox Code Playgroud)
IHttpModule
工作该IHttpModule的接口看起来像:
public interface IHttpModule
{
void Init(HttpApplication context);
void Dispose();
}
Run Code Online (Sandbox Code Playgroud)
该Init()
方法用于将事件处理程序订阅到应用程序事件,并且该Dispose()
方法在应用程序完成后清除模块.
System.Web
定义一个IHttpModule
名为的实现System.Web.SessionState.SessionStateModule
.如果未在web.config中禁用会话,则会连接以下事件处理程序:
// app is the current HttpApplication ;
app.AddOnAcquireRequestStateAsync(this.BeginAcquireState, this.EndAcquireState);
app.ReleaseRequestState += this.OnReleaseState;
app.EndRequest += this.OnEndRequest;
Run Code Online (Sandbox Code Playgroud)
根据正在运行的会话模式,会话的工作方式不同,但要理解的关键是在SessionStateModule.BeginAcquireState
方法中检索和创建会话,并且该方法与AcquireRequestState
事件异步连接.
System.Web
定义一个IHttpModule
名为的内部实现System.Web.Caching.OutputCacheModule
.该Init()
方法如下:
void IHttpModule.Init(HttpApplication app)
{
if (RuntimeConfig.GetAppConfig().OutputCache.EnableOutputCache)
{
app.ResolveRequestCache += new EventHandler(this.OnEnter);
app.UpdateRequestCache += new EventHandler(this.OnLeave);
}
}
Run Code Online (Sandbox Code Playgroud)
该OnEnter
方法评估缓存参数并查找与请求匹配的缓存响应.该OnLeave
方法缓存可缓存的响应.您需要知道的一件事是,如果OnEnter
方法成功检索到缓存的响应,它会调用实例上的CompleteRequest()方法HttpApplication
.此方法的文档为:"使ASP.NET绕过所有事件并在HTTP管道执行链中进行过滤,并直接执行EndRequest事件".因此,将跳过CompleteRequest()
在调用时间和EndRequest()
事件之间发生的任何事件.
SessionStateModule
订阅SessionStateModule.BeginAcquireState
应用程序的AcquireRequestState
活动,所以这是创建和检索,其中会话.OutputCacheModule
订阅OutputCacheModule.OnEnter
应用程序的ResolveRequestCache
活动,所以这就是缓存的响应进行检索,并在那里CompleteRequest()
被调用.这意味着,下列事件将永远不会触发的缓存请求:MapRequestHandler/PostMapRequestHandler
; AcquireRequestState/PostAcquireRequestState
; PreRequestHandlerExecute
; IHttpHandler.ProcessRequest
; PostRequestHandlerExecute
; ReleaseRequestState/PostReleaseRequestState
; UpdateRequestCache/PostUpdateRequestCache
; 而且,LogRequest/PostLogRequest
.HttpApplication.CompleteRequest()
调用,则AcquireRequestState
事件永远不会触发,并且永远不会创建会话.是否在页面上禁用输出缓存以支持控件是一种可行的解决方案取决于:(1)使用会话的代码是在控件中还是在页面中; (2)您的应用程序实例需要支持多少负载; (3)应用程序或其支持基础结构中存在哪些其他缓存机制.根据您的基础设施,可能还有其他因素需要考虑.例如,ASP.NET会话的执行和行为可能会有很大差异,具体取决于会话状态模式以及环境是否负载平衡.此外,如果您正在运行像Varnish这样的HTTP加速器缓存(例如),则在先前输出缓存的ASP.NET分页上启用会话可能会更改从省略会话到附加属于其他用户的陈旧会话的行为.这只是一个假设的例子,但重点是在做出这些决定时可能还需要考虑其他因素.