在浏览器中加载虚拟目录名称时,AcquireRequestState 中的 Session 为空,但在加载时不为空 Default.aspx
Session is null in AcquireRequestState when loading virtual directory name in browser, but not null when loading Default.aspx
我有一个 ASP.NET 4.0 WebForms 应用程序。我需要访问 HttpContext.Current.Session
并在 Global.asax 中的 AcquireRequestState
事件(或其后的事件)中设置一个值,我发现了一个奇怪的行为。
假设我在 IIS 中有一个名为 Foo
的虚拟目录(在我的例子中是版本 7)。因为我有 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 中是否有我遗漏的配置设置,或者这是一个 bug/forgotten 功能?
another question 的回答暗示了 IIS 不会为每种请求加载会话,例如样式表不需要会话。发生此行为的原因可能是 IIS 无法提前判断该文件夹名称是否会导致执行 aspx 文件或是否会传送静态 HTML 文件?
更新: 我什至尝试重新排序 IIS 查找的默认文档,以便 "default.aspx" 位于列表的顶部,例如
- default.aspx
- Default.asp
- Default.htm
- ...
我仍然遇到同样的问题。
更新:
事件处理程序只被触发一次,因为它会导致 NullReferenceException
。我已经做了一些额外的阅读,我知道 ASP.NET 会为每个请求触发这些事件,即使是 CSS 或 JavaScript 文件。此外,静态文件不会加载会话对象,因为没有访问会话的代码,因此不需要加载该对象。尽管如此,第一个请求是请求网页,需要session,session为null
@DmytroShevchenko 问:
First add a guard check if (HttpContext.Current.Session != null)
so that there is no NullReferenceException
thrown. Then try to see, maybe the event will be fired a second time, with a session available.
修改后的代码:
void Application_AcquireRequestState(object sender, EventArgs e)
{
if (HttpContext.Current.Session != null)
{
HttpContext.Current.Session["key"] = "value";
}
}
我在if
语句处设置了一个断点。我看到这个事件触发了 4 次:
- 会话为空
- 会话为空
- 会话不为空
- 会话为空
每次继续单步执行代码时,只有当它开始执行 Default.aspx
及其代码隐藏时,我才有可用的会话。我实际上在 Firefox 中打开了网页并正在监视网络请求。第一个请求是 http://localhost/Foo/
.
接下来我也在Application_BeginRequest
中设置了一个断点并得到了以下事件:
- 开始请求
- 获取请求状态
- 开始请求
- 获取请求状态
- 开始请求
- AcquireRequestState(会话不为空)
- 执行Default.aspx(/Fooreturns对浏览器的响应)
- 开始请求
- AcquireRequestState(会话再次为空)
在 #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 请求挂起等待响应。
实际情况是,在将请求传输到页面之前发生的某些事件会触发此事件。同样,此事件可以由 ASPX 页面之外的其他页面引发。我认为你需要做一些事情:
- 设置
AutoEventWireUp
to false
in your page's code (in default.aspx). It seems odd and unrelated, but apparently this can resolve your issue.
- 检查
null
。真的。因为在所有事件中,您只对那些实际上 具有 会话状态的 ASPX 页面(或类似页面)的事件感兴趣。由于来自用户的每个 true 请求总是会创建一个会话,因此您可以简单地过滤这些请求而不必担心错过某些事件。如您所见,在每个周期中,总是至少有一个具有设置会话的事件命中。
- 使用
PostAcquireRequestState
,这是更自然的使用(或使用PreRequestHandlerExecute
),因为在那个事件中,所有状态都保证被设置和填充。
我发现 a discussion 通过显式 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";
}
}
我认为你的请求 url 不包含“.aspx”,对吗?
IIS7+ 版本有配置 whitch 在认为请求处理程序不是 managedHandler
时不会使用 "SessionStateModule"
所以解决方法很简单
找到你的 web.config,然后添加 属性
<modules runAllManagedModulesForAllRequests="true">
....
</modules>
runAllManagedModulesForAllRequests="true" 告诉 asp.net 无论如何都要使用所有模块
希望有帮助
当资源出现编译错误时,即使在 Application_PostAcquireRequestState
中,会话也会为空
我有一个 ASP.NET 4.0 WebForms 应用程序。我需要访问 HttpContext.Current.Session
并在 Global.asax 中的 AcquireRequestState
事件(或其后的事件)中设置一个值,我发现了一个奇怪的行为。
假设我在 IIS 中有一个名为 Foo
的虚拟目录(在我的例子中是版本 7)。因为我有 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 中是否有我遗漏的配置设置,或者这是一个 bug/forgotten 功能?
another question 的回答暗示了 IIS 不会为每种请求加载会话,例如样式表不需要会话。发生此行为的原因可能是 IIS 无法提前判断该文件夹名称是否会导致执行 aspx 文件或是否会传送静态 HTML 文件?
更新: 我什至尝试重新排序 IIS 查找的默认文档,以便 "default.aspx" 位于列表的顶部,例如
- default.aspx
- Default.asp
- Default.htm
- ...
我仍然遇到同样的问题。
更新:
事件处理程序只被触发一次,因为它会导致 NullReferenceException
。我已经做了一些额外的阅读,我知道 ASP.NET 会为每个请求触发这些事件,即使是 CSS 或 JavaScript 文件。此外,静态文件不会加载会话对象,因为没有访问会话的代码,因此不需要加载该对象。尽管如此,第一个请求是请求网页,需要session,session为null
@DmytroShevchenko 问:
First add a guard check
if (HttpContext.Current.Session != null)
so that there is noNullReferenceException
thrown. Then try to see, maybe the event will be fired a second time, with a session available.
修改后的代码:
void Application_AcquireRequestState(object sender, EventArgs e)
{
if (HttpContext.Current.Session != null)
{
HttpContext.Current.Session["key"] = "value";
}
}
我在if
语句处设置了一个断点。我看到这个事件触发了 4 次:
- 会话为空
- 会话为空
- 会话不为空
- 会话为空
每次继续单步执行代码时,只有当它开始执行 Default.aspx
及其代码隐藏时,我才有可用的会话。我实际上在 Firefox 中打开了网页并正在监视网络请求。第一个请求是 http://localhost/Foo/
.
接下来我也在Application_BeginRequest
中设置了一个断点并得到了以下事件:
- 开始请求
- 获取请求状态
- 开始请求
- 获取请求状态
- 开始请求
- AcquireRequestState(会话不为空)
- 执行Default.aspx(/Fooreturns对浏览器的响应)
- 开始请求
- AcquireRequestState(会话再次为空)
在 #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 请求挂起等待响应。
实际情况是,在将请求传输到页面之前发生的某些事件会触发此事件。同样,此事件可以由 ASPX 页面之外的其他页面引发。我认为你需要做一些事情:
- 设置
AutoEventWireUp
tofalse
in your page's code (in default.aspx). It seems odd and unrelated, but apparently this can resolve your issue. - 检查
null
。真的。因为在所有事件中,您只对那些实际上 具有 会话状态的 ASPX 页面(或类似页面)的事件感兴趣。由于来自用户的每个 true 请求总是会创建一个会话,因此您可以简单地过滤这些请求而不必担心错过某些事件。如您所见,在每个周期中,总是至少有一个具有设置会话的事件命中。 - 使用
PostAcquireRequestState
,这是更自然的使用(或使用PreRequestHandlerExecute
),因为在那个事件中,所有状态都保证被设置和填充。
我发现 a discussion 通过显式 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";
}
}
我认为你的请求 url 不包含“.aspx”,对吗?
IIS7+ 版本有配置 whitch 在认为请求处理程序不是 managedHandler
时不会使用 "SessionStateModule"所以解决方法很简单
找到你的 web.config,然后添加 属性
<modules runAllManagedModulesForAllRequests="true">
....
</modules>
runAllManagedModulesForAllRequests="true" 告诉 asp.net 无论如何都要使用所有模块
希望有帮助
当资源出现编译错误时,即使在 Application_PostAcquireRequestState
中,会话也会为空