在浏览器中加载虚拟目录名时,Session在AcquireRequestState中为空,但在加载Default.asp
本文关键字:加载 Default asp AcquireRequestState 虚拟 浏览器 Session | 更新日期: 2023-09-27 18:17:15
我有一个ASP。NET 4.0 WebForms应用程序。我需要访问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>
当我在浏览器中访问http://localhost/Foo/Default.aspx
时,它工作得很好。当我访问http://localhost/Foo/
时,我得到一个NullReferenceException
,在那里我设置了会话的值。唯一的变化是浏览器中的URL。它们最终会到达相同的页面,但框架的行为会根据URL是否只包含文件夹名称或是否包含aspx文件而有所不同。
检查if (HttpContext.Current.Session != null)
对我来说不是一个选项,因为我需要在每个请求的会话上设置一个值,这是不可协商的。
在IIS中是否有我遗漏的配置设置,或者这是一个错误/忘记的功能?
对另一个问题的回答暗示了IIS不会为每一种请求加载会话,例如样式表不需要会话。也许发生这种行为是因为IIS无法提前判断文件夹名称是否会导致执行aspx文件或是否会传递静态HTML文件?
Update:我甚至尝试重新排序IIS查找的默认文档,以便"默认"。"Aspx"在列表的最前面,例如
- default . aspx
- Default.asp
- Default.htm
- …
我还是遇到同样的问题。
更新:
事件处理程序只被触发一次,因为它导致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";
}
}
我在if
语句处设置了一个断点。这个事件我看了5次:
- 会话为空
- 会话为空
- session not null
- 会话为空
当每次继续执行代码时,只有当它开始执行Default.aspx
和它的代码隐藏时,我才有一个可用的会话。实际上,我在Firefox中打开了网页,并监视网络请求。第一个请求是http://localhost/Foo/
。
接下来,我在Application_BeginRequest
中设置了一个断点,并得到了以下事件:
- BeginRequest
- AcquireRequestState
- BeginRequest
- AcquireRequestState
- BeginRequest
- AcquireRequestState (session is not null)
- 默认执行。aspx (/Foo返回一个响应给浏览器)
- BeginRequest
- AcquireRequestState (session再次为null)
#9时,浏览器中对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
的AJAX请求挂起等待响应。
我发现有一个讨论关于通过显式URL提供页面和提供默认文档之间的区别。
在MVC和WebAPI中,引入了一个新的HttpModule: ExtensionlessUrlHandler。我相信您的事件多次触发(并且只有一次会话可用)可能是由该模块或ASP的其他(重新)路由逻辑引起的。. NET实际上重定向ASP。. NET处理Default.aspx
.
此外,正如您自己提到的,这些事件可以为静态文件请求触发。
最重要的是,您不应该依赖于每次事件触发时会话都可用。但是可以放心地假设,在提供ASP服务时,至少可以访问一次会话。网络页面。因此,您的代码应该是这样的:void Application_AcquireRequestState(object sender, EventArgs e)
{
if (HttpContext.Current.Session != null)
{
HttpContext.Current.Session["key"] = "value";
}
}
实际情况是,在将请求传输到页面之前发生的某些事件触发了此事件。类似地,此事件可以由ASPX页面以外的其他页面引发。我认为你需要做几件事:
- 设置
AutoEventWireUp
为false
在您的页面的代码(在default.aspx)。这看起来很奇怪,但显然这可以解决你的问题。 - 检查
null
。真的。因为在所有事件中,您只对那些源自ASPX页面(或类似页面)的事件感兴趣,这些事件实际上具有会话状态。由于来自用户的每个true请求总是创建一个会话,因此您可以简单地对这些请求进行过滤,而不必担心错过某些事件。正如你所看到的,在每个周期中,总是至少有一个事件命中具有设置会话。 - 使用
PostAcquireRequestState
,这是更自然的事情使用(或使用PreRequestHandlerExecute
),因为在那个事件,所有的状态都保证被设置和填充。
我认为您的请求url不包含"。aspx",对吧?
IIS7+版本有一个配置,当它认为请求处理程序不是managedHandler时,不会使用"SessionStateModule"
所以解决方法很简单
找到你的网页。配置,然后添加属性
<modules runAllManagedModulesForAllRequests="true">
....
</modules>
runAllManagedModulesForAllRequests="true"告诉asp.net使用所有模块
hope helpfull
当资源有编译错误时,即使在Application_PostAcquireRequestState