I have this piece of code:
var thisUser = Session["user"];
if (thisUser == null)
{
LogFile.Log("Logging out");
Response.Write("xp");
}
I am trying to track down why sometimes when I play with the system for a few minutes and suddenly the user session variable gets null.
It happens randomly in different scenarios.
I do not set the Session["user"] to null at any point.
Session timeout is set to 20 minutes.
I do not call Session.Clear() at any point.
Any ideas\thoughts\things I should look at as to why is it may happening?
I am using Firefox if that to any help.
The system is built with asp.net.
For more info please ask.
are you calling the same host? if the base URL is different the server will treat this as different users. for example:
http://localhost/path/to/resource and http://localhost:80/path/to/resource
both point to the same resource, but the requests are different and the session cookie will be different, or not present.
An easy way to test this is to launch your browser's developer toolbar and monitor the network traffic. compare the URLs to make sure they are the same base path and the same session cookie is passed in the request.
First of all this looks like C# and ASP.NET, not classic ASP. Now if you never clear the session yourself and the server (or the app pool) is never restarted, then the only way to lose the session is to clear the browser's cookies.
Editing the web.config will recycle the app pool, which clears the session info.
We have an ASP Web-Forms site that we update frequently.
However, any time we modify any classes stored in the App_Code folder, this causes an App Pool Recycle and loses all of our session state, causing our users to be logged out.
This means that any time we need to make changes in app code it needs to be around 2:00 in the morning to minimize user impact.
Now, since I value my sleep I was wondering if there is any workaround for this behaviour?
I've tried switching the application to use StateServer mode for Session State.
This seems to work as long as the class being changed is not currently in use.
However if the class is in use it results in every-bodies session being lost.
What is best practice in this case for a heavily used website?
Am I condemned to late nights every time we need to fix a bug in our classes?
Thanks in advance for any response...
You will need sessionState setting cookieless="false" in addition to mode="StateServer".
In addition you need a fixed machine key, so a recycle won't generate a new machine key but uses the same key. If a new key is generated all previous sessionIds can't be decrypted, so the link to the sessionState is lost.
Check https://technet.microsoft.com/en-us/library/cc755177(WS.10).aspx for how to configure/generate a machine key.
This is an example from msdn, so don't use this in production, but generate your own key:
<machineKey
validationKey="32E35872597989D14CC1D5D9F5B1E94238D0EE32CF10AA2D2059533DF6035F4F"
decryptionKey="B179091DBB2389B996A526DE8BCD7ACFDBCAB04EF1D085481C61496F693DF5F4"
/>
In the end you need something like this in your Web.config or your Machine.config if you want to set the same key on machine level.
What exactly happens in System.Web.Mvc.MvcHandler.BeginProcessRequest()? I have a MVC project running on Azure, and with NewRelic it's showing 500ms-1500ms for BeginProcessRequest(). I don't use SessionState (<sessionState mode="Off" /> in web.config).
I have already looked at this similar question: What happens in BeginProcessRequest()?
What exactly is happening here?
Thanks!
There are a couple of things other than session state related thread agility that can cause long BeginRequest times.
If New Relic cannot get deep/detailed enough data into the transaction, it rolls it up into the BeginRequest method time. This can also occur if the time could be spent in the database or an external service. This is also demonstrated with asynchronous activity that cannot be tied back to the transaction that fired it.
There are also instances when the application is first started where you can see long BeginRequest times. For your Azure application, you can try turning your app pool's start mode to "Always On" to see cut down on times where your app might have to stop/start, causing long begin requests.
Here is a document that contains some additional information, and here is a forum post where users without session states have had similar issues.
A website I am working on is very data centric. Some reports take more than an hour to complete. Whenever a user submits a request for a report, a new thread is created which generates the report. The user is then redirected to a page which says that the report in progress, and to please refresh to download the report. If the user again refreshes the page and the report is still in progress, the same message is shown; otherwise a download link is provided.
All report/user relations are saved in the application variable. That works fine, except when the user is inactive for more than 20 min (while the report is being processed), and then the user is logged out; if the user logs in again, the report can still be downloaded.
I do not want to increase the session expiration time, but I need to stop the expiration if the user has something going in background, like a report being processed.
In Session_End I am able to retrieve the the userid and match it in Application["work"] to see the user has pending work or not.
However, I am clueless as to how I can defer the session end in the above case?
Edit: Every one has suggested as a workaround from 'maintaining a contact' to 'using query string'. 'Maintaining the contact' looked the most promising to me but it fails in the following scenarios: a. When browser is closed/computed goes in standby mode during lunch, etc. b. When user goes to another non-asp.net section (it's a legacy site).
Isn't It possible to cancel the Session_End event itself?
The short answer
There is currently (that I know of) no simple way to extend the life of a single ASP.NET session. There is one possible solution: use a custom Session-State Store Provider!
The long answer
First things first: Start with something that is already built! Use the sample Session-State Store Provider (and its tutorial) provided by Microsoft. This sample Session-State Store Provider uses Microsoft Access as its back end; although, because it uses ODBC connections, you can have virtually any database back end supported through your installed ODBC drivers.
This sample Session-State Store Provider is simply a custom version of what ASP.NET uses internally (with the exception that ASP.NET's runs in-memory).
Secondly: Let's prepare the Access Database requirements, and the configuration.
Create the table as specified in the tutorial and in the comments of the file:
CREATE TABLE Sessions
(
SessionId Text(80) NOT NULL,
ApplicationName Text(255) NOT NULL,
Created DateTime NOT NULL,
Expires DateTime NOT NULL,
LockDate DateTime NOT NULL,
LockId Integer NOT NULL,
Timeout Integer NOT NULL,
Locked YesNo NOT NULL,
SessionItems Memo,
Flags Integer NOT NULL,
CONSTRAINT PKSessions PRIMARY KEY (SessionId, ApplicationName)
)
NOTE: If you want to use SQL Server, simply replace Text(...) with varchar(...), YesNo with bit, and Memo with varchar(MAX).
Add/update your web.config with the following (you can use connectionstrings.com to help you generate a connection string):
<configuration>
<connectionStrings>
<add name="OdbcSessionServices" connectionString="DSN=SessionState;" />
</connectionStrings>
<system.web>
<sessionState
cookieless="true"
regenerateExpiredSessionId="true"
mode="Custom"
customProvider="OdbcSessionProvider">
<providers>
<add name="OdbcSessionProvider"
type="Samples.AspNet.Session.OdbcSessionStateStore"
connectionStringName="OdbcSessionServices"
writeExceptionsToEventLog="false" />
</providers>
</sessionState>
</system.web>
</configuration>
Third: Adding a function that will extend for more than the specified Timeout.
Make a copy of the ResetItemTimeout function, and name it ResetItemTimeout2:
var ExtendedTotalMinutes = 2 * 60; // hours * minutes
public override void ResetItemTimeout2(HttpContext context, string id)
{
OdbcConnection conn = new OdbcConnection(connectionString);
OdbcCommand cmd =
new OdbcCommand("UPDATE Sessions SET Expires = ? " +
"WHERE SessionId = ? AND ApplicationName = ?", conn);
cmd.Parameters.Add("#Expires", OdbcType.DateTime).Value
= DateTime.Now.AddMinutes(ExtendedTotalMinutes); // IMPORTANT!! Set your total expiration time.
cmd.Parameters.Add("#SessionId", OdbcType.VarChar, 80).Value = id;
cmd.Parameters.Add("#ApplicationName", OdbcType.VarChar, 255).Value = ApplicationName;
try
{
conn.Open();
cmd.ExecuteNonQuery();
}
catch (OdbcException e)
{
if (WriteExceptionsToEventLog)
{
WriteToEventLog(e, "ResetItemTimeout");
throw new ProviderException(exceptionMessage);
}
else
throw e;
}
finally
{
conn.Close();
}
}
Fourth: Supporting the extension of a single ASP.NET Session!
Whenever you need to extend a session, call the ResetItemTimeout function as follows:
using Samples.AspNet.Session;
// from inside a User Control or Page
OdbcSessionStateStore.ResetItemTimeout2(this.Context, this.Session.SessionID);
// --or--
// from anywhere else
OdbcSessionStateStore.ResetItemTimeout2(System.Web.HttpContext.Current, System.Web.HttpContext.Current.Session.SessionID);
Footnotes
Read the comments on the page with the sample Session-State Store Provider;
There is one potential good entry about a Mistake in GetSessionStoreItem when using GetItem.
Another good one is that Timestamps should be UTC.
There are obvious performance/maintainability improvements that could be done (especially with having duplicate code in ResetItemTimeout and ResetItemTimeout2).
I have not tested this code!
Edits
I realized I missed the part where you want to extend more than the Timeout - answer has been fully updated.
Added footnotes section.
Maintain a contact with the server will avoid Session Timeout.
Create a empty Web service and run that in your server then call the web service by your site by JQuery by the interval of some seconds is enough to keep the session alive
May be this solution will help you..
Try this link for full details : Prevent Session Timeout in ASP.NET
While desperately looking for defering the session_end event I think it seems impossible?
The easiest work around that I was able to come with was 'Using Cookies' and modifying my authentication logic.
I implemented a method for writing a guid key to the cookie named admin when ever user requested for the report with expiration of 9 hour(Max time office will be open for work).
I save this guid with user id in a seperate table.
In the master page where i was checking for session userid I implemented another method to check for any cookie named admin. If it is found i set session to the user id saved in table else i redirect them to login page as before it was happening.
It seems to work like magic. But I need to know is this a right thing?
What you can do is set the Session timeout to a higher value when you detect that a report has been requested that will take a long time. This of course supposes that you can calculate whether a report will take a long time to run. If so, you can do this before you kick off the thread:
Session.Timeout = 120 // set timeout to two hours for this session only
Apart from pinging a page or service through Ajax, there really is no other way. (unless not relying on sessions at all is an option).
This is because of the way sessions are maintained: the ASP.NET runtime detects a session when the request contains a cookie. This cookie is set at every request / response and will contain an expiration date.
If in your initial request you set an expiration of 20 minutes and the user closes the browser or is inactive for more than 20 minutes there is no way on the server side you can detect which session the request belongs to.
So, to answer your question whether you can cancel the session_end, no you cannot do that as that code runs server side and it cannot access the client cookie. It's a simple event that is fired twenty minutes after you last set the cookie. This is completely asynchronous from the client-side.
The solution I proposed is a workaround that could work if you know how to calculate the duration (at least approximately).
Another solution, but way more complicated, would be to save the reports and make a separate section for the user where he can see all his reports. That way, even if the session times out, he can log back in and go to his history and retrieve the report.
It's best not to rely on Session_end as it doesn't always fire, such as when the worker process recycles or an uncaught exception occurs, i.e. it is basically killed / bounced.
If you want to revive a session then it seems that the best way is to store the user data somehow and totally manage the cache yourself.
It seems from your reply to previous posts that the additional network activity and subsequent page time load increase when using sql state management are unacceptable, and the difference between using sql server state provider to using a session server such as Microsoft AppFabric would be negligible, however it seems a distinct possibility that if you were to use the session server of AppFabric coupled with it's caching, things could be sped up a lot.
P.S. In general doing away with sessions would seem like the most efficient solution, see John Han's answer in this post just about sums it up sessions are bad mmkay.
In order for a session to stay alive, something (not necessarily the user's browser) has to make a request to your app with that user's ASP.NET_SessionId cookie every so often.
What if you had some code that saves the ASP.NET_SessionIds of the users you are interested in, and then have a windows service that requests a page on your app with the required ASP.NET_SessionId(s) every 20 minutes or so.
see http://erlend.oftedal.no/blog/?blogid=41 for some info about this cookie
Are you using FormsAuthentication? If so, you could increase the timeout for the authentication ticket, which will prevent the login screen even after the session has expired.
At the beginning of the request you could check the user through the ticket
After get the user if the session is null it means the user has been offline for while, you the can check the work in progress for that user.
If the user has a work in progress, load session values that you might need it and redirect them to the work in progress or report to download.
If the user has nothing, expire the ticket and redirect them to login page or just keep them logged in and reload session values.
The timeout for the authentication ticket is pretty big
http://msdn.microsoft.com/en-us/library/system.web.configuration.formsauthenticationconfiguration.timeout.aspx
Cheers
I'd suggest increasing the session timeout instead of trying to find a way around it. There's an interesting thread about session and form timeouts here
I suggest that you don't depend on sessions at all .. you can depend on the query string by adding a new GUID variable and use that variable value with the application object to map the user requested file(s) with the GUID value .. this way .. the user will always be able to download the file since he have the link to the file that is mapped to the application object and no need to handle any session timeout.
Why do not you try to show the loading file progress bar and inside that one you can use the logic of checking status of file downloaded so far. It will have two advantage , as you are hitting your website , Session will not expire at the same time you are giving the useful information back to end user.
I need to maintaing the Session throughout the day? On or before session expires, how do I enforce session throughout the day without giving any session timeout either in IIS or web.config?
Note: Default Session Timeout in IIS – 20 minutes.
Thanks in Advance
The first thing you can do is decouple the session from the process by using a SQL (or other database) session state server that holds the serialized copy of the session data attached to a session id. Then you could use a persistent cookie to pass the session id back and forth. Any session that expires could then be regenerated or reinstated.
Since you're wanting to maintain a session all day (which is innately insecure), we'll assume that most security considerations have already been thrown out. If you're concerned about replay attacks, you could use an HMAC to validate cookie session requests by having the session id, datetime, username (if that's part of your data), maybe IP address in a string followed by a one-way salted hash of this data. This way you rehash the data and compare the hash sent with the request with the generated hash from that data to see if the request is valid.
Forcing the page to be refreshed every 10 minutes or so by javascript. The session timeouts are how long after the last requested page, the session becomes invalid. When you refresh the page every 10 minutes or so, the session is extended for 20 minutes on every refresh.
If you refuse to change the setting in the web.config to a longer value, you could try to force the browser to refresh within a short time of the session timeout (eg at 17 minutes). There might be other nifty ways.
If you can find a way to do without the session, it will save you pain later. Either use a caching strategy (memcached) or look at your resource usage.
eg Do you really need to serialise X into the session?
Use StateServer instead of InProc
This delegates all session handling to a separate database and removes it from the servers process. This will mitigate problems with eating up server resources which then allows you to increase the session timeout to 24 hours.
I believe this is the only viable solution.
Peiter is on the right track -- making fake requests to keep things alive. You definitely don't want to refresh the page, that leads to unwanted updates and such. You don't even need to refresh part of the page. You just need to send an ajax request every X minutes while a user has a browser open to an IHttpHandler that does have session state enabled. This is very, very effective -- we've got one app which is compltely dependent upon sessions for everything that has a 5 minute session timeout. And a session heartbeat that fires every 4.5 minutes. Its been in production upwards of 3 years and we have not lost a session yet. And yes, session state is stored in process in this case -- the use of sessions is so heavy we don't want to wait for them to go out to SQL and back.
PS: protip -- make sure to make the request and response unique; caching kicks in otherwise in certain browsers rendering this trick ineffective.
put a ajax call into a timer, to a method which does nothing "", that's how even the user is on the page but not doing anything means "totally inactive", would not log out, we have implemented the same logic and resolved our problem, our target was 3 to 4 hours, and we did not want to change the value in web.config or using any other way cause of some reasons.
that ajax call would be in a "timer", set the timer time to "any".