Wednesday, July 9, 2008
ASP.NET Session Timeouts
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.
Wednesday, July 2, 2008
Use Google Page Creator to store files for blogger
Thread safety in C# and ASP.NET
I found that it can be difficult to consistently reproduce the bug in web code, though I think it can be done. To make things easier, I simulated the web. I created two threads to create the race condition. I didn't use a Threading Pool, but I think this is close enough, and illustrates the point while reliably and consistently reproducing the race condition.
First I guess I should explain a little bit about what a race condition is. Let's assume you have two threads. They could be two web sessions as each connection to the your ASP.NET application is handled by a thread from the thread pool. The issues comes when those two threads try to access any shared resource. Thread-A sets a value for example, has some kind of delay, and while Thread-A is processing / delaying Thead-B comes along and changes the shared resource before Thread-A has a chance to use / retrieve value from the shared resource. Then when Thread-A finally has a chance to access the shared resource without coding for thread-safety, Thread-A will assume it was the only one that had used the shared resource and thus it will get data it was not expecting. It is probably a good idea to always only allow one object access to a shared resource and only allow one calling object at a time actually call the method.
I think the easiest way to see this is to look at the output of a program I wrote to see what was actually going on.
Thread-A-Starting
Thread-A-Spawned
Thread-A-Entering Critical Section
Thread-A-New
Generated Value is: 1907360620
Set New Value: 1907360620
Thread-A-Waiting.... forcing race condition
Thread-B-Starting
Thread-B-Spawned
Thread-B-Entering Critical Section
Thread-B-New
Generated Value is: 209463673
Set New Value: 209463673
Thread-B-Waiting.... forcing race condition
Get New Value: 209463673
Thread-A-CriticalSection() returns: 209463673 (Important Line *******)
Thread-A-Exiting Critical Section
Get New Value: 209463673
Thread-B-CriticalSection() returns: 209463673 (Important Line *******)
Thread-B-Exiting Critical Section
The important thing to note is that the return value for both threads is the last value that was set, and this is because both threads entered the critical section of code at the same time or near the same time. When this happens, they basically step on each other's feet and you get bad results.
Below is the same output but there is a lock on the critical section of code so that only one thread can enter it at a time.
Thread-A-Starting
Thread-A-Spawned
Thread-A-Entering Critical Section
Thread-A-New Generated Value is: 1483178371
Set New Value: 1483178371
Thread-A-Waiting.... forcing race condition
Thread-B-Starting
Thread-B-Spawned <Press any key to remember>
Get New Value: 1483178371
Thread-A-CriticalSection() returns: 1483178371 (Important Line *******)
Thread-A-Exiting Critical Section
Thread-B-Entering Critical Section
Thread-B-New Generated Value is: 249049990
Set New Value: 249049990
Thread-B-Waiting.... forcing race condition
Get New Value: 249049990
Thread-B-CriticalSection() returns: 249049990 (Important Line *******)
Thread-B-Exiting Critical Section
The important thing to notice is that the values set by each thread are also retrieved by each respective thread. This is what we want to happen. You will also notice that even though the threads start together or close together, they take turns using the shared resource. In fact, one thread uses the shared resource until it is done with it, and while the other thread waits to use it.
In C# there is something called a Monitor class that locks and unlocks shared resources. They have simplified the syntax much in the same way that they have with database connectivity. If you are familiar with the using () block in your code. You know it implicitly handles the closing a connection for example (even if there is an exception). Well, the lock () block does the same thing for the Monitor class. It basically guarantees that the object will be unlocked even if there is an exception. It does NOT handle deadlocks, though you can do so with try-catch-finally and the Monitor class because it has a TryEnter and allows you to specify how long to wait for a lock before giving up (thus breaking a deadlock).
Below is a snippet of how locks work.
private static Object objLock = new Object();
public void CriticalSection()
{
lock (objLock)
{
// use shared resource here
}
}
Things to note here are that the objLock variable is both static (this extremely important) and it is also private so that no one else can unlock the lock (which would defeat its purpose). You can use different lock variables for locking different parts of your code. The smaller number of lines of code you lock at a time the better your performance will be. So, you may want to create different locks for different methods if they are not accessing the same shared resource.
If you would like a much more in-depth and more technical explanation of the how and why I suggest what I suggest I recommend you check
Monday, June 30, 2008
101st Posting
Friday, June 27, 2008
A safe way to save entities in HP OpenView Service Desk (OVSD) web-api
If you have have worked with HP OpenView Service Desk (OVSD) web-api, you may have noticed sometimes it throws an exception that says "There are no changes to save." when you call the save() method on entities such as Servicecall, Workorder, Change, etc. This is annoying and fairly useless thing to know if you ask me. This should not be an exception in my opinion if you call save too often, especially since the api doesn't support transactions. Instead of repeating the same try catch blocks everywhere in my code, it became obvious to me that the safest thing to do is to just write a very simple method to call instead of the standard save() method on an entity. What the method below does is allows you to pass virtually any type of entity from HPOV web-api objects that have a save() method or more specifically inherit from IApiEntity object (this is at least all the major ones). Now instead of ... myServiceCallObject.save(); just call the method and pass it the object you want to save. SaveEntity(myServiceCallObject); This is clean and reduces unexpected bugs caused by this "exception" :) private void SaveEntity(IApiEntity entity) throws Exception { try{ entity.save(); } catch (Exception ex) { if (!ex.getMessage().equalsIgnoreCase("There are no changes to save.")) { throw ex; } } }