Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Session is null in AcquireRequestState when loading virtual directory name in browser, but not null when loading Default.aspx

I have an ASP.NET 4.0 WebForms application. I need to access HttpContext.Current.Session and set a value in the AcquireRequestState event (or an event after it) in Global.asax, and I've found a peculiar behavior.

Let's say I have a virtual directory in IIS (version 7 in my case) called Foo. In that I have Default.aspx as the home page. A sample Global.asax file is below:

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

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

When I visit http://localhost/Foo/Default.aspx in my browser, it works just fine. When I visit http://localhost/Foo/ I get a NullReferenceException where I set the value on the session. The only change is the URL in the browser. They end up hitting the same page, but the framework behaves differently based on whether or not the URL contains just a folder name, or if it contains an aspx file.

Checking if (HttpContext.Current.Session != null) is not an option for me, because I need to set a value on the session with every request, which is non negotiable.

Is there a config setting in IIS that I'm missing, or is this a bug/forgotten feature?

An answer for another question hinted at the fact IIS does not load the session for every kind of request, for example style sheets don't need a session. Maybe this behavior is happening because IIS can't tell ahead of time if that folder name will result in executing an aspx file or if it will deliver a static HTML file?

Update: I even tried re-ordering the default documents that IIS looks for so that "default.aspx" was at the top of the list, e.g.

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

And I am still getting the same problem.

Update:

The event handler is only getting fired once because it is resulting in a NullReferenceException. I've done some additional reading and I know ASP.NET triggers these events for every request, even for CSS or JavaScript files. Additionally, the session object is not loaded for static files because there is not code that accesses the session, thus no need to load the object. Even so, the very first request is the request for the web page, which will need the session, and the session is null.

@DmytroShevchenko asked:

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.

Modified code:

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

I set a break point at the if statement. I saw this event fire 4 times:

  1. session is null
  2. session is null
  3. session not null
  4. session is null

When continuing to step through the code each time, only when it started executing Default.aspx and its code-behind did I have a session available. I actually had the web page open in Firefox and was monitoring the network requests. The first request was for http://localhost/Foo/.

Next I set a breakpoint in Application_BeginRequest as well and got the following events:

  1. BeginRequest
  2. AcquireRequestState
  3. BeginRequest
  4. AcquireRequestState
  5. BeginRequest
  6. AcquireRequestState (session is not null)
  7. Execute Default.aspx (/Foo returns a response to the browser)
  8. BeginRequest
  9. AcquireRequestState (session is null again)

At #9 the AJAX request in the browser to 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 is hanging waiting for a response.

like image 631
Greg Burghardt Avatar asked Oct 12 '15 19:10

Greg Burghardt


3 Answers

I found a discussion about the differences between serving a page by its explicit URL and serving a default document.

With MVC and WebAPI, a new HttpModule was introduced: ExtensionlessUrlHandler. I believe that your event firing multiple times (and only once with session being available) may be caused by this module or other (re)routing logic of ASP.NET that actually redirects ASP.NET to handle Default.aspx.

Also, as you yourself mentioned, these events can be triggered for static file requests.

The bottom line is, you should not rely on session being available every time your event is fired. But it is safe to assume that you can access session at least once when serving an ASP.NET page. Hence, this is how your code should look like:

void Application_AcquireRequestState(object sender, EventArgs e)
{
    if (HttpContext.Current.Session != null)
    {
        HttpContext.Current.Session["key"] = "value";
    }
}
like image 151
Dmytro Shevchenko Avatar answered Oct 22 '22 09:10

Dmytro Shevchenko


I think your request url is not contain ".aspx", right?

The IIS7+ version has the config whitch will not use the "SessionStateModule" when it think the request handler is not managedHandler

So the solution is easy

Find your web.config, then add the property

<modules runAllManagedModulesForAllRequests="true">
     ....
</modules>

runAllManagedModulesForAllRequests="true" tell asp.net use all modules anyway

hope helpfull

like image 1
moker Avatar answered Oct 22 '22 08:10

moker


What is happening is that certain events that occur prior to transferring the request to the page, trigger this event. Similarly, this event can be raised by other than ASPX pages. I think you need to do a few things:

  • set AutoEventWireUp to false in your page's code (in default.aspx). It seems odd and unrelated, but apparently this can resolve your issue.
  • check for null. Really. Because from all events, you are only interested in those events that originated from an ASPX page (or similar) that actually have a session state. Since every true request from a user always creates a session, you can simply filter for these without worrying that you miss certain events. As you have seen, at every cycle, there is always at least one event hit that has a set Session.
  • use PostAcquireRequestState, it is the more natural thing to use (or use PreRequestHandlerExecute), because on that event, all state is guaranteed to be set and filled.
like image 1
Abel Avatar answered Oct 22 '22 08:10

Abel