I see a lot of questions regarding Session state in ASP.NET and invariably the majority of problems are related to the volatility of InProc Session state.
InProc Session state in ASP.NET works using an internal memory based list object. Everytime something gets added to the state it gets added to the Session state of this list. Because it is memory based it is fully dependent on the lifetime of the AppDomain that your Web application runs in.
You might think, no big deal – my app is stable and it doesn’t restart. But are you sure of that? Seriously, in IIS 6 and with ASP.NET there are lots of things that can restart your current application without you explicitly knowing about it.
web.config
The most common scenario is settings in Web.Config. Any change made in web.config causes the AppDomain to unload and the Session state with it. If you change an AppSettings value (if you use that) or if you change a flag like DebugMode for a temporary debug to find that online bug that just won’t repro in your test environment – you will blow away the AppDomain and Session state with it.
IIS 6 Application Pool cycling
IIS 6 also includes a number of health checking services. In fact, most ISPs I work with have their IIS 6 Application Pools (which are the host containers in which ISAPI and ASP.NET applications run) set to recycle once a day. Usually these will be at odd hours in the morning but still. If you’re one of the nightowls who likes to buy underwater goggles at 3am in the morning you might just get zinged. I'd be pissed if I spend 10 minutes shopping for items and am in the middle of the checkout process and your session dies just before you click the ‘Do it, do it, do it’ button, and you have to ‘do it’ all over again...
West Wind Web Monitoring and Integrity checks
In my own applications that I run I have a West Wind Web Monitoring service that monitors (using our own West Wind Web Monitor software) the 20 or so apps that are running on my server for failures both in the raw HTTP state as well as to the content they are returning. These are varied applications, some ASP.NET, some Fox Web Connection applications and even a couple of ASP apps. My monitor checks all of these and if it detects a failure for more than two check cycles it tries to restart the Web Server. This doesn’t happen very frequently, but even once a month is one too many if Session state is lost as a result of it!
Code Updates
Finally, when you update code on your ASP.NET Codebehind assembly (ie. your Web Project’s main assembly) on the live site, the AppDomain also gets cycled as well! Yup… AppDomains load assemblies dynamically, but once loaded they can never be unloaded, so when the assembly is replaced on the server Asp.NET detects the change and unloads the entire AppDomain. You can change pages without a recycle (because page classes are dynamically compiled and named), but the main precompiled assembly has fixed names for the classes and since you can't load the same class ontop of the existing one the AppDomain must be unloaded.
You can try this out with this C# CodeBehind code:
public class ApplicationPoolsAndThreads : System.Web.UI.Page
{
protected System.Web.UI.HtmlControls.HtmlForm Form1;
protected string ApplicationId = "";
protected int ThreadId = 0;
protected string DomainId = "";
protected string ThreadInfo = "";
private void Page_Load(object sender, System.EventArgs e)
{
// Put user code to initialize the page here
this.ApplicationId = ((HowAspNetWorks.Global)
HttpContext.Current.ApplicationInstance).ApplicationId ;
this.ThreadId = AppDomain.GetCurrentThreadId();
this.DomainId = AppDomain.CurrentDomain.FriendlyName;
this.ThreadInfo = "ThreadPool Thread: " + System.Threading.Thread.CurrentThread.IsThreadPoolThread.ToString() +
"<br>Thread Apartment: " + System.Threading.Thread.CurrentThread.ApartmentState.ToString();
bool IsThreadPoolThread = System.Threading.Thread.CurrentThread.IsThreadPoolThread;
// *** Simulate a slow request so we can see multiple
// requests side by side.
System.Threading.Thread.Sleep(3000);
}
}
Add a page that embdeds the field values:
<table border="1" cellpadding="5" style="WIDTH: 480px" align="center">
<tr>
<td style="WIDTH: 121px"><strong>Application Id: </strong>
</td>
<td>
<%= this.ApplicationId %>
</td>
</tr>
<tr>
<td style="WIDTH: 121px"><strong>Thread Id:</strong>
</td>
<td>
<%= this.ThreadId %>
</td>
</tr>
<tr>
<td style="WIDTH: 121px"><strong>Domain Id:</strong>
</td>
<td>
<%= this.DomainId %>
</td>
</tr>
<tr>
<td style="WIDTH: 121px"><strong>Thread Info:</strong>
</td>
<td>
<%= this.ThreadInfo %>
</td>
</tr>
</table>
Run this code (without the debugger attached) a few times and notice the Domain Id stays steady. If you hit from multiple locations you can see multiple threads active etc.
Now go make a change in the project so it forces a recompile, and recompile the project and make sure the assembly is updated. Watch the Domain Id, then refresh and you’ll see that once the DLL is updated the AppDomain has been replaced with a new one and your InProc Session state is gone.
This particular issue will be addressed in ASP.NET 2.0 with the loony compilation scheme that compiles every page into its own uniquely named assembly rather than one huge codebehind assembly. Not sure if that’s a good or bad thing as it opens up a number of other issues.
Can you get away with it? I don’t think so
Anyway, I don’t think that any application that relies on Session state can reasonably ignore all of these points. Yet many people try to run with InProc anyway, either out of ignorance because it is after all the default or because they feel it’s worth the extra performance.
InProc state is definitely considerably faster than either the state server or SQL Server State storage. No doubt about it that in process memory usage is faster than anything that has to cross process and possibly machine boundaries (both state and Sql state often run on a separate machine but neither has to).
However, I think that it’s really no contest. If you’re using Session state I would assume that the state is fairly vital to your application otherwise you’d stick the information into Cookie or other client carried statebag. So assuming your app relies on session state to keep it running right, how much is that extra performance of InProc Session state worth to you? Enough to piss off even a small number of customers who loose their shopping cart or other tracking mechanism?
The alternatives are the ASP.NET Session Server which provides an IP network interface that’s fairly efficient if run on the local machine, and SQL Server State which writes the session state into a SQL Server table which is the slowest of all approaches but also the most reliable and most useful if you need to take statistics on your session interface. You can read more about the mechanisms in this earlier WebLog entry.
Another alternative is to not rely so much on Session state in the first place. In many of my older applications I didn’t use any Session state at all, instead the application has a current user table that tracks the necessary information in a similar manner. It requires a database too, so in the big scheme of things this is as slow as state too, but in my experience much of the information that ends up in the state is information that the application needs to capture anyway either for logging or often times for the flow of the application. So the round trip to the database would happen anyway. Finding a way to standardize how the data gets persisted into this internal state table (using a business object front end perhaps) can give you the same functionality of Sesison without using a Session mechanism at all…
Ultimately it all depends on your application, but for me there’s never been an occasion where InProc session was appropriate as there were always issues that eventually would cause problems for the user in the front end if the Session died.
Other Posts you might also like