在浏览器中加载虚拟目录名时,会话在AcquireRequestState中为空,但在加载Default.aspx时不为null

Gre*_*rdt 12 c# asp.net iis session webforms

我有一个ASP.NET 4.0 WebForms应用程序.我需要在Global.asax中访问HttpContext.Current.Session并设置AcquireRequestState事件(或事件后面的事件)中的值,并且我发现了一种特殊的行为.

假设我在IIS中有一个虚拟目录(在我的情况下是版本7)Foo.在那我Default.aspx作为主页.示例Global.asax文件如下:

<%@ Application Language="C#" %>

<script runat="server">
    void Application_AcquireRequestState(object sender, EventArgs e)
    {
        HttpContext.Current.Session["key"] = "value";
    }
</script>
Run Code Online (Sandbox Code Playgroud)

当我http://localhost/Foo/Default.aspx在浏览器中访问时,它运行正常.当我访问时,http://localhost/Foo/我得到一个NullReferenceException我在会话上设置值的地方.唯一的变化是浏览器中的URL.它们最终会访问同一页面,但框架的行为会有所不同,具体取决于URL是否只包含文件夹名称,还是包含aspx文件.

检查if (HttpContext.Current.Session != null)对我来说不是一个选项,因为我需要在会话中为每个请求设置一个值,这是不可协商的.

IIS中是否存在我缺少的配置设置,或者这是一个错误/被遗忘的功能?

另一个问题的答案暗示IIS不会为每种请求加载会话,例如样式表不需要会话.也许这种行为正在发生,因为IIS无法提前告诉该文件夹名称是否会导致执行aspx文件或者它是否会传递静态HTML文件?

更新:我甚至尝试重新排序IIS查找的默认文档,以便"default.aspx"位于列表的顶部,例如

  1. Default.aspx的
  2. Default.asp的
  3. Default.htm的
  4. ...

我仍然遇到同样的问题.

更新:

事件处理程序只被触发一次,因为它导致了一个NullReferenceException.我已经做了一些额外的阅读,我知道ASP.NET会为每个请求触发这些事件,即使对于CSS或JavaScript文件也是如此.此外,没有为静态文件加载会话对象,因为没有访问会话的代码,因此无需加载对象.即便如此,第一个请求是对网页的请求,该请求将需要会话,并且会话为空.

@DmytroShevchenko问:

首先添加一个警卫检查,if (HttpContext.Current.Session != null)以便没有NullReferenceException抛出.然后尝试看一下,也许这个事件将会第二次被解雇,会话可用.

修改后的代码

void Application_AcquireRequestState(object sender, EventArgs e)
{
    if (HttpContext.Current.Session != null)
    {
        HttpContext.Current.Session["key"] = "value";
    }
}
Run Code Online (Sandbox Code Playgroud)

我在if声明中设定了一个断点.我看到这个事件发生了4次:

  1. session为null
  2. session为null
  3. 会话不为空
  4. session为null

每次继续遍历代码时,只有当它开始执行Default.aspx并且其代码隐藏时,我才有可用的会话.我实际上在Firefox中打开了网页,并监控网络请求.第一个请求是http://localhost/Foo/.

接下来我也设置了一个断点,Application_BeginRequest并得到以下事件:

  1. 的BeginRequest
  2. 的AcquireRequestState
  3. 的BeginRequest
  4. 的AcquireRequestState
  5. 的BeginRequest
  6. AcquireRequestState(会话不为空)
  7. 执行Default.aspx(/ Foo返回对浏览器的响应)
  8. 的BeginRequest
  9. AcquireRequestState(会话再次为null)

在#9,浏览器中的AJAX请求http://localhost:54859/8fad4e71e57a4caebe1c6ed7af6f583a/arterySignalR/poll?transport=longPolling&connectionToken=...&messageId=...&requestUrl=http%3A%2F%2Flocalhost%2FFoo%2F&browserName=Firefox&userAgent=Mozilla%2F5.0+(Windows+NT+6.1%3B+WOW64%3B+rv%3A41.0)+Gecko%2F20100101+Firefox%2F41.0&tid=4&_=1445346977956正在等待响应.

Dmy*_*nko 12

我找到关于通过显式URL提供页面与提供默认文档之间的区别的讨论.

使用MVC和WebAPI,引入了一个新的HttpModule:ExtensionlessUrlHandler.我相信你的事件多次触发(并且只有一次会话可用)可能是由这个模块或ASP.NET的其他(重新)路由逻辑引起的,它实际上重定向了ASP.NET来处理Default.aspx.

此外,正如您自己提到的,可以为静态文件请求触发这些事件.

最重要的是,您不应该在每次触发事件依赖会话.但是可以安全地假设您在提供ASP.NET页面时至少可以访问一次会话.因此,这就是你的代码应该是这样的:

void Application_AcquireRequestState(object sender, EventArgs e)
{
    if (HttpContext.Current.Session != null)
    {
        HttpContext.Current.Session["key"] = "value";
    }
}
Run Code Online (Sandbox Code Playgroud)