Wednesday, July 9, 2008

ASP.NET Session Timeouts

In ASP.NET there are lots of timeouts. In this blog entry I will be covering in great detail Session timeout due to the complexity of the issue and the fact that I can never remember where all the setting are and what they are for. I am not covering other timeouts except Script Timeout.

SIDE NOTE: Web services that you consume have timeouts before ASP.NET stops waiting for a response from a web service, but I am not covering that here. The web services on the server side have timeouts that are independent of the ASP.NET consuming the web service. I am also not covering timeouts associated with database connections or authentication either. It is however important that all these timeouts be be compatible with each other, otherwise you will get undesirable behavior. For example, don't set your execution time to less than the database timeout. Or don't set the application recycle to be less than the session timeout.


SessionState Timeout
This is the number of minutes before an ASP.NET user session is terminated. It must be an integer, and it is in minutes. The default is to terminate the session after 20 minutes and the application will throw an exception when accessing an terminated session. Another way to think of this is that it is the time between requests for a given session (which is per user) before a session is terminated.

I recommend reading Idle Timeout section below to see how these are related.


Using Web.config
<system.web>
<sessionState timeout="20" />
<system.web>


Using IIS
You can get to the setting by: Open IIS | Properties on Web Site | ASP.NET tab | Edit Configuration... (or Edit Global Configuration to change for more than one site) | State Management tab.

Here you will see a textfield with a label that says "Session timeout (minutes) with a default value of 20 minutes.

Session Timeout Event
When the session times out it fires an event called: Session_End and then when the user hits the page again (after it has expired or the first time), it will start a new session and the Session_Start event is called. It is important to know that the only thing you can really do in the Session_End event is do clean up. This is because this event fire even if a user doesn't hit a page again. In other words, if a session times out due to inactivity, the Session_End is fired even if the user never refreshes the page, etc. It is independent of the page lifecycle. These events are defined in the Global.asax file.


Detecting when a session has timed out
The short answer to this is that you have a session time when the following conditions are met:
Context.Session != null
AND Context.Session.IsNewSession == true
AND Page.Request.Headers["Cookie"] != null
AND Page.Request.Header["Cookie"].indexOf("ASP.NET_SessionId") >= 0

The long answer is read this blog for more details and sample code: http://www.eggheadcafe.com/articles/20051228.asp

and http://aspalliance.com/520


Idle Timeout


IIS 6.0 (and probably 7) has a setting that controls how idle processes are handled.

This can also affect the session timeout indirectly. This is the case when let's say you have the Idle timeout set to 10 minutes to save resources. If your site is not used a lot and say that the only user using your site stopped using it 10 minutes ago, this means that your application will get recycled. One of the side effects of an application getting recycled is that all sessions are terminated also. So, in this case even if your session is set to timeout say in 30 minutes, under some conditions (little traffic), it is effectively 10 minutes.

If you have low traffic on your application I strongly recommend you set the Idle Timeout to at least as long as your session timeout, otherwise you will effectively be limiting the session time to the Idle Timeout when there is very little traffic on your site. This is in my cases not the desired behavior.

Here is what the help docs in IIS say:
"Idle timeout limits helps conserve system resources by terminating unused worker processes by gracefully closing idle processes after a specified idle duration. This allows you to better manage the resources on particular computers when the processing load is heavy, when identified applications consistently fall into an idle state, or when new processing space is not available."


Open IIS | Properties on the App Pool you are using | Performance tab
Here you will see a setting that says: "Shutdown worker processes after being idle for 20 (time in minutes)" where 20 is the default.

NOTE: Some shared hosting provider don't allow you to access or change this value. In this case one option is to at a set interval ping your application (from a program running on another computer) to keep it alive and thus not get recycled. Though some providers may change the setting so that all application are recycled at particular times as well. Best of luck working with shared hosting providers. I would love to have feedback on a shared hosting provider that has settings that are good for low traffic sites.


Recycle Worker Processes
IIS 6.0 (and probably 7) has a another setting that you can set that determines when the worker processes are recycled.

Open IIS | Properties on the App Pool you are using | Recycling tab
Here you will see a setting that says:
"Recycle worker processes (in minutes):" with a default value of 1740 which is 29 hours.

Classic ASP - Session State timeout in IIS
There is a setting in IIS 6 (and probably 5 and 7) that controls the session timeout in minutes if the user does not refresh or change pages in the specified number of minutes. This is for Classic ASP pages NOT ASP.NET. So don't worry about this for ASP.NET. I added it here since it can be confusing You can get to the setting by: Open IIS | Properties on Web Site | Home Directory tab | Configuration button | Options tab.The field label is "Session timeout:" and the value is 20 minutes as the default value.


Classic ASP - Script timeout in IIS
There is a setting in IIS 6 (and probably 5 and 7) that controls the script timeout in seconds. This is the time that ASP allows a script to run before it stops the script and records the event in the Event Log. This is for Classic ASP pages NOT ASP.NET. So don't worry about this for ASP.NET. I added it here since it can be confusing. You can get to the setting by: Open IIS | Properties on Web Site | Home Directory tab | Configuration button | Options tab.The field label is "ASP script timeout:" and the value is 90 seconds as the default value.


Alternate Timeout handling Mechanisms
In some cases you want to inform the user about session timeout status or automatically have it renew, or maybe any other sort of action. You can use JavaScript / AJAX to accomplish this. If you have access to IIS configuration and you are something like an Intranet you can set your application pool to not recycle if you have enough resources, and set an extremely long session timeout and then handle the timeout on the client side instead. This appears to be a much better experience for the user in general. However, you can also use these techniques to just improve the experience the user has when a session times out.

This article goes into great detail so I won't. The article (
http://ajaxpatterns.org/Timeout) does such a wonder job of explaining it. It is complete with demos as well.

Here is a nice link (http://www.pascarello.com/AjaxSessionTimer.aspx) to a timeout warning message box that shows when your session is about to expire. It does not get past the issue of the application being recycled so be sure to adjust that as recommended above.

Here is a link to stuff to make your UI look really cool: http://script.aculo.us/



Script Timeout
While this is not really session timeout, it could affect it in rare instances so I am mentioning it here for completeness. This is the maximum time an .aspx page can run before timing out. It can be set in two places. Either the web.config (or machine.config for all sites) or via code using Script.ScriptTimeout. If you have debug enabled in web.config then the Server.ScriptTimeout is set to 30000000 seconds (or 347.2 days). Otherwise the default is 90 seconds. This setting is most important if you have long requests that need processing like file uploads, etc. In general the defaults are probably ok.

Using the web.config
This sets the timeout to 3 minutes.
<compilation debug="false"/>
<httpRuntime executionTimeout="180" />

Using code
Server.ScriptTimeout

Using IIS
You can get to the setting by: Open IIS | Properties on Web Site | ASP.NET tab | Edit Configuration... (or Edit Global Configuration to change for more than one site) | Application tab.

Here you will see a textfield with a label that says "Request Execution timeout (seconds):" with a default value of 110 seconds.

IMPORTANT NOTE: Be sure to uncheck the "Enable debugging" checkbox next to this field, otherwise, the value will be ignored and set to the 30,000,000 seconds that debugging defaults to.










22 comments:

JB said...

Thank you. It took me longer than it should have to find out where in Web.Config to set the SessionTimeout.

Mike said...

Thanks Brent!

For about a year now I was trying to figure out why sometimes my session would work at 45 min and why sometimes people would randomly get logged out sooner than that. It was the Idle Timeout!!!! They should default that to the Session timeout on IIS.

Brent V said...

Mike,

Thanks for your feedback! Yeah... I think this subject is more difficult than it needs to be.

Brent

Danny said...

If you experience random timeouts for your sessions (ie timeout quicker than specified in sessionstate and idle timeouts), you may want to check if your application pool in IIS 6.0 has any 'Memory recycling' values selected and they are set up to some low sizes both for virtual or used memory.

If e.g you have 200 Mb and the application reaches that limit in 5 minutes (e.g) the recycle happens and any sessions are killed sooner than expected...

Brent V said...

Danny,

That is an excellent point! Thank you for adding to usefulness of this article. It is greatly appreciated.

Brent

Danny said...

You're welcome. Actually I wanted everybody be aware of this when I experienced that issue. I was about to run mad: both sessionState and idle was properly configured for 30 minutes but in our case the session was expiring every few seconds (randomly between 15 to 20 seconds) and this was because the memory limit ranges were pretty low... When I took this option out everything was working fine... :)

I hope this helps many people that is complaining about random session timeouts...

Mike Irving said...

Knowing that all of these context-specific timeouts can be set for both the script and the session, for classic asp as well as asp.net web applications is really interesting and useful. Thanks.

Brent V said...

Hi Mike,

It is indeed interesting, and it is also a pain in the but to troubleshoot and remember. I use this info to help me when I have issues.

Thanks for the feedback,

Brent

scuty said...

Hi all!

I am doing all that is written is this article but for some reason when the session timeout the Session_End is not been fired all the time.

My session is set to InProc and I manually changed the timeout on 30 mins also I did all that this article states and still the same result.

Any help - tips would be highly appreciated.

Thank you.

Brent V said...

Hi scuty,

It is hard to say what your issue is. I don't have an easy answer for you. The best thing I can suggest is try a very simple application from scatch with nothing in it really and see how that behaves. Build from there until you recreate your issue.

Sorry I don't have better advice. Please let me know if you figure it out. I am curious.

Thx,

Brent

scuty said...

Hi again,

I have verified all the code and I tested and it worked fine ... But there are some cases when it would simply not fire the Session_End when the session timeout. And I also think is totally random.

I had the same think in old ASP and it works great and it still works on our old web sites but it doesn't work all the time in .NET.

Thanks for your help anyway.

Dave said...

Not sure if your Recycling worker process section is correct. You specify that the worker process is recycled after the specified minutes "of inactivity". I think it is just recycled not matter what after the specified number of minutes.

Great article though, thanks.

Brent V said...

Dave,

Thanks for the feedback. I believe you are correct. The process recycling is regardless of inactivity. Good find. Thank you. I have made the correction.

Brent

Nandu said...

Hi Deve,
Its a very good article . One of our application is getting eregular session time out . I need to check out now again. I was suspecting a memory leak.

Thanks.

Brent V said...

Nandu,

Thank you for your feedback. Good luck, and glad to help.

Thanks,

Brent

Michael said...

Hi,I'm getting a session timeout.My .config file as 20 minutes, but after 10 minutes the session has timeout.I Have check the worker process and the recycler time is set to 25 minutes.I also check the ISS event viewer an i haven't found any unexpected error at this time.
Why could be the session Timeout?

Thanks

Zeeshan Umar said...

It is really help full for me to figure out why sessions are timed out unexpectedly.

Anonymous said...

Thanks alot, thats help me

William said...

NCache is an extremely fast in-memory distributed cache for .NET. NCache also provides an ASP.NET Session State storage that is reliable (thru replication) and scalable.

Muhammad Azeem said...

This is a nice article..
Its easy to understand ..
And this article is using to learn something about it..

c#, dot.net, php tutorial, Ms sql server

Thanks a lot..!
ri80

Anonymous said...

I was researching issues at a client site related to session timeout on a legacy application. This was quite useful. Thanks yas!

Unknown said...

Hi, useful article. These settings can be set in thousands of places: * On Internet Information Services -> Web Sites (right-click -> Properties)
* On your website underneath Web Sites (right-click -> Properties)
* On an individual file (but only for Execution Timeout, as far as I can see)
* In web.config
* In code (but where do I put this code???)

My question is how do conflicting values override each other?