如果页面被缓存,为什么不创建会话?

时间:2013-11-04 18:56:12

标签: asp.net session iis-7.5 outputcache

问题:当从缓存中提取请求的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");

非常感谢任何相关信息。

2 个答案:

答案 0 :(得分:7)

为了理解输出缓存请求为什么不创建会话,您需要了解ASP.NET Application Life Cycle事件。基础是在每个请求期间可能触发的定义的HttpApplication events系列。这些事件通常由HttpModule实现或Global.asax file使用事件处理程序订阅。

并非每个应用程序事件都会在每个请求中触发,但触发的事件将始终按照定义的顺序触发。在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

IHttpModule如何运作

IHttpModule界面如下所示:

public interface IHttpModule
{
    void Init(HttpApplication context);
    void Dispose();
}

Init()方法用于将事件处理程序订阅到应用程序事件,并且Dispose()方法在应用程序完成后清除模块。

ASP.NET会话如何工作

System.Web定义了名为System.Web.SessionState.SessionStateModuleIHttpModule实现。如果未在web.config中禁用会话,则会连接以下事件处理程序:

// app is the current HttpApplication ;
app.AddOnAcquireRequestStateAsync(this.BeginAcquireState, this.EndAcquireState);
app.ReleaseRequestState += this.OnReleaseState;
app.EndRequest          += this.OnEndRequest;

会话的工作方式不同,具体取决于正在运行的会话模式,但要理解的关键是在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);
    }
}

OnEnter方法评估缓存参数并查找与请求匹配的缓存响应。 OnLeave方法缓存可缓存的响应。您需要知道的一件事是,如果OnEnter方法成功检索到缓存的响应,它会调用HttpApplication实例上的CompleteRequest()方法。此方法的文档为:“使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分页上启用会话可能会更改从省略会话到附加属于其他用户的陈旧会话的行为。这只是一个假设的例子,但重点是在做出这些决定时可能还需要考虑其他因素。

答案 1 :(得分:0)

显然这是默认的.NET行为。如果您创建一个新的应用程序,启用会话,缓存一个aspx页面,然后让一个新用户拉出该页面的缓存版本,他们将没有会话/ cookie。

作为一种解决方法......我认为我们只会禁用页面输出缓存并使用更积极的控制缓存。