Most likely the session is lost because the Application Pool is recycled for some reason. There are several thing which could cause such a recycle.
- web.config being changed
- files in \bin or \App_code directories are modified
- any of the conditions in Process Model for the Application Pool is met. Like a memory limit being hit, or a request-queue being full.
- antivirus or similar modifying the above files
Because of all of this I've researched what it takes to move the session state handling out of the w3wp.exe process, and it's actually not that difficult.
Session state can primarily be handled in three ways. In-Process, with State server or in SQL server. There is also a Custom way, but that's out of our scope for now.
Moving from In-process to using the State server is as easy as modifying a single line in your web.config, and making sure the Windows Service called ASP.NET State Service is running. The web.config should include a sessionState element, like this.
<configuration>
<system.web>
<sessionState mode="StateServer"
stateConnectionString="tcpip=127.0.0.1:42424"
cookieless="false"
timeout="20">
</sessionstate>
</system.web>
And that's it!
What we've gained by doing this is that the changes listed above will no longer cause a user to be logged out. You can even call iireset.exe, and the session is still kept alive. What we've lost is about 15% performance since the session needs to be serialized out from the w3wp.exe process, and handled by the aspnet_state.exe process.
If the ASP.NET State Service is restarted it will loose all the sessions since they are kept in-memory by the service.
We can also take this one step further by storing the sessions in a SQL database instead. By doing this we gain even more recilience because we can reboot the server which handles the sessions, and users are still maintaining their sessions when the server is online again.
In order to set up SQL handling of the sessions you'll need to modify the web.config again, but also have a SQL database to store the sessions in.
<system.web>
<configuration>
<sessionState mode="SQLServer"
stateConnectionString="tcpip=127.0.0.1:42424"
sqlConnectionString= "data source=127.0.0.1;
user id=sa;password=secret"
cookieless="false"
timeout="20">
</sessionstate>
</system.web>
</configuration>
And the SQL database is created by a tool that ships with the .NET Framework.
C:\>aspnet_regsql.exe -S localhost -U sa -P secret -ssadd -sstype p
That command will create a database on the local SQL server called ASPState where all the sessions are stored. The drawback of storing sessions in SQL is that you loose about 25% performance compared to the InProc mode.