I have an object that I need to store in the session.
At the beginning of each request, I copy the object to the HttpContext.Current.Items collection so it can be reused during the request.
During the request, the state of the object can be modified, so I need to write it back out to the session so that it can be used for the next request.
I tried updating it via the HttpApplication.EndRequest event handler, but I discovered that the HttpContext.Current.Session is null by this point.
Is there another event handler in HttpApplication that occurs after a request has been processed, but within which I can still access the HttpContext.Current.Session?
The session is available from the HttpApplication.PostRequestHandlerExecute event, which according to the documentation:
"Occurs when the ASP.NET event handler (for example, a page or an XML Web service) finishes execution."
This page was helpful in understanding the sequence of HttpApplication events:
http://blog.dotnetclr.com/archive/2007/03/14/HttpApplication-pipeline-demystified.aspx
Related
Question: Why is there no session created (and session cookie) when an aspx page requested is pulled from cache?
Background Information
I've made quite a few google searches, but I can't find anything that indicates that this is the intended behavior. Our desired behavior is that a new session/cookie are always generated regardless of whether the page requested is pulled from cache.
We are caching pages using the following code. (.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");
Any relevant information would be greatly appreciated.
In order to understand why an output-cached request will not create a session, you need to understand a little bit about the ASP.NET Application Life Cycle, the events . The basics are that are a defined series of HttpApplication events that may fire during each request. These events are typically subscribed to using event handlers by either HttpModule implementations or a Global.asax file.
Not every application event fires on every request, but the events that do fire will always fire in the defined order. The order of events that fire on 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
How an IHttpModule Works
The IHttpModule interface looks like:
public interface IHttpModule
{
void Init(HttpApplication context);
void Dispose();
}
The Init() method is used to subscribes event handlers to the application events and the Dispose() method cleans up after the module when the application is done with it.
How ASP.NET Sessions Work
System.Web defines an IHttpModule implementation named System.Web.SessionState.SessionStateModule. If the session is not disabled in the web.config, the following event handlers get wired up:
// app is the current HttpApplication ;
app.AddOnAcquireRequestStateAsync(this.BeginAcquireState, this.EndAcquireState);
app.ReleaseRequestState += this.OnReleaseState;
app.EndRequest += this.OnEndRequest;
Sessions work differently depending on what session mode is running but the key thing to understand is that sessions are retrieved and created in the SessionStateModule.BeginAcquireState method and that method is wired up asynchronously to the AcquireRequestState event.
How Output Caching Works
System.Web defines an internal IHttpModule implementation named System.Web.Caching.OutputCacheModule. The Init() method looks like:
void IHttpModule.Init(HttpApplication app)
{
if (RuntimeConfig.GetAppConfig().OutputCache.EnableOutputCache)
{
app.ResolveRequestCache += new EventHandler(this.OnEnter);
app.UpdateRequestCache += new EventHandler(this.OnLeave);
}
}
The OnEnter method evaluates the cache parameters and looks for a cached response that matches the request. The OnLeave method caches cacheable responses. The one thing you need to know is that if the OnEnter method is successful in retrieving a cached response, it calls the CompleteRequest() method on the HttpApplication instance. The documentation for this method reads: "Causes ASP.NET to bypass all events and filtering in the HTTP pipeline chain of execution and directly execute the EndRequest event". So, any events that occur between the time that CompleteRequest() is called and the EndRequest() event are skipped.
Why is session not created if page is cached?
The SessionStateModule subscribes SessionStateModule.BeginAcquireState to the application's AcquireRequestState event, so that is where sessions are created and retrieved.
The OutputCacheModule subscribes OutputCacheModule.OnEnter to the application's ResolveRequestCache event, so that is where cached responses are retrieved and where CompleteRequest() gets called. That means that the following events will never fire for a cached request: MapRequestHandler/PostMapRequestHandler; AcquireRequestState/PostAcquireRequestState; PreRequestHandlerExecute; IHttpHandler.ProcessRequest; PostRequestHandlerExecute; ReleaseRequestState/PostReleaseRequestState; UpdateRequestCache/PostUpdateRequestCache; and, LogRequest/PostLogRequest.
If a cached response is retrieved, then HttpApplication.CompleteRequest() is called, the AcquireRequestState event never fires, and the session is never created.
What to do about it?
Whether disabling output cache on pages in favor of controls is a viable solution depends on: (1) whether the code that uses the session is in the controls or in the pages; (2) how much load your application instance needs to be able to support; and, (3) what other caching mechanisms exist in either the application or its supporting infrastructure. Depending on your infrastructure, there may be other factors to consider. For example, ASP.NET sessions can perform and behave very differently depending on the session state mode and on whether the environment is load balanced or not. Also, if you happened to be running an HTTP accelerator cache like Varnish (for example), enabling sessions on a previously output-cached ASP.NET paged might change the behavior from omitting a session to attaching a stale session that belongs to a different user. This is just a hypothetical example, but the point is that there may be additional factors to consider when making these kinds of decisions.
Apparently this is default .NET behavior. If you create a new app, enable session, cache an aspx page, and then have a new user pull the cached version of that page, they will be given no session/cookie.
As a workaround...I think we'll just disable page outputcache and use more aggressive control caching.
How to get session value in code file while session is created in httphandler .it gives error like Object reference not set to an instance of an object.
The session is connected with a page request, to work is require to read the cookie of the user from the browser, or the url in case that is with out cookies.
So in the asp.net session if you do not have the httphandler, you can not have the session, because you can not know who is calling and see the page at that time.
Maybe in a custom solution session, you can send the session id to some other code with out the httphandler and use that id to read the session data, but the asp.net did not give this option.
In my page I'm regenerating session id on every button click to go to the next page. I've already saved username in my session variable (session["uname"]=txtusername.text) in the time of log in. But as I'm regenerating new session id ,session["uname"] is having null reference because of new session id.That's why I want to set the session variable value using a Global.asax in session start function.
void Session_Start(object sender, EventArgs e)
{
session["uname"]=here;
}
But here in Global.asax page I'm unable access any value from my log in page..
The main problem is accessing any value in global.asax from code behind.
How can I solve this......Plz help......Thanking in advance..............
HttpContext.Current.Session["uname"]=here;
First don`t write business logic in Global.asax .
I want to point you out 3 basic things:
When session_start() called
How sessions are maintained
Where you should set your session variables.
For the following details I am assuming you have login.aspx, login.aspx.cs:
As you know HTTP is stateless protocol, so every request is new request.
So for every request session_start() will get executed.
When user request the resource for the first ever time, unique session will be generated, and cookie containing session Id will be sent to client.
For any further request from the user, HTTP client will pass the cookie to server, so user can be tracked by the server. This is how session works.
Now lets come to your code you are setting Session["uname"] in session_start() of Gloabl.asax, keep in mind that Globlax.asax is called before the page life-cycle begins
so it does not have access to page data.
Instade you should set your Session["uname"] in login.aspx.cs file. Here check if users credentials are correct then:
set Session["uname"]=value.
Now for every other request Session["uname"] for that user will be available. And you can also retrieve/update the values at session_start() of Global.asax too.
I have a IHttpHandler that acts as a source to a jQuery Autocomplete input field. In the constructor of the handler I generate an index that remains fairly static between request (needs to be rebuilt maybe once a day).
How can I cache the the index between calls? Debugging indicates that the constructor is called for each request. I've set IsReusable to "false".
Your handler is passed an HttpContext which means it has access to the application cache (e.g. context.Cache["Foo"] = myVal) and can save values there. However, you can also save the value in Session (e.g. context.Session["Bar"]) if your handler implements the IRequiresSessionState interface.
HttpHandlers have a special propert IsReusable. You can override that property in your Handler implementation and set it to return True. IsReusable is a value indicating whether another request can use the IHttpHandler instance.
So first time when the handler is accessed the Handler instance is created and upon next request the same instance serves the request back - so your caching trick will work right in this case.
http://msdn.microsoft.com/en-us/library/system.web.ihttphandler.isreusable.aspx
which event is the most suitable to check for Session expired? i'm trying to trap each server request, and if Session is null, redirect to a different page.
You can determine if a new session is being created by hooking Session_OnStart - http://msdn.microsoft.com/en-us/library/ms178583(VS.80).aspx
You can handle the Session_OnStart
event by adding a subroutine named
Session_OnStart to the Global.asax
file. The Session_OnStart subroutine
is run at the beginning of a request
if the request begins a new session. A
new session will be started if a
request is made that does not contain
a SessionID value or if the SessionID
property contained in the request
references a session that has expired.
This will tell you effectively when a new session is being created, regardless of if the user just arrived or the session had expired.
It would be hard to reliably differentiate between both scenarios. I guess you could try to get a hold a the session id in the either the session cookie or embedded in the url (cookieless), but you would need to check it before getting to the above event, and later check whether the request had a session id originally. Check if you can get to the session id in the cookieless version, because it is stripped out of the urls asp.net gives you (not sure if early in the lifecycle you get to see it).
This is often best achieved by using a base Page class for all otehr classes, and implementing this in the Page_Load method.
Use BasePage class, which inherits from Page class. Let every aspx page inherits that BasePage class. In BasePage class, override OnInit event, in which you can check for Session or Cookie, and redirect user to login page (for example).
I use this approach for all mine webforms apps, because it's easy to implement and use.