Handle session timeout loss of data - c#

In a module I wrote I store in the session the items the user added to his cart.
How would you handle this situation: The user adds a new item to his cart after the session timedout?
I can redirect to the homepage but then I'm causing the redirect to happen even when the session wasn't in use. like when the user isn't logged in, or his cart was empty.
How do you handle session timeout in your applications?

In this case, I might not use the built in ASP.NET Session provider. Instead you could set a persistent cookie for the customer's shopping cart session with an encrypted ID that maps to a session stored in the database, which stores the contents of the cart.
This way, you don't need to worry about timeouts, the session will continue for the lifetime of the cookie.
(If you really need to use ASP.NET Session, maybe you've already got code that uses it, then you could set the timeout to a very large number and configure the Session state provider to use SQL Server.)

Your page can have a javascript timer running and when the time runs out the page is redirected to another page, say login, with query string parameters as flags. When the Login screen is called with x flag, then the shopping cart is saved to the database for safe keeping. The key is to have the timeout be shorter than the session timeout.
ADDED:
Javascript on each page:
<body onload="PageLoad();">
<script type="text/javascript">
function PageLoad()
{
var t = setTimeout("ExceuteTimeOutTransfer()", 15000);
}
function ExceuteTimeOutTransfer()
{
window.location.href = "http://localhost/webplaying/Login.aspx?timeout=Y";
}
</script>
Code Behind on Login Page:
protected void Page_Load(object sender, EventArgs e)
{
if (Request.QueryString["timeout"] != null)
{
if (Request.QueryString["timeout"].ToUpper() == "Y")
{
SaveCart();
}
}
}
private void SaveCart()
{
lblResult.Text = "Cart Saved";
}

An alternative would be to store the cart in a cookie.

Related

Implement logout on every page

I want to implement logout option on every view of my webpage.For this i assigned null to my session variable. And also remove the data in cache. But I studied that to remove the data from cache put some extra burden on web server because no data is stored in cache...
So, what can be alternative to this problem.
Create a _Layout page and keep your Login/Register/Logout there. You can check by creating a default Web MVC application and see how login/register/logout rendering in every page.
There are many ways to clean cache by using java script.
I like this way,
<script>
function ClearHistory()
{
var backlen = history.length;
history.go(-backlen);
window.location.href = loggedOutPageUrl //Pass your Index Page
}
</script>
Or else the easiest way is just clear the cache in LogOff() method, just like bellow,
{
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetExpires(DateTime.UtcNow.AddHours(-1));
Response.Cache.SetNoStore();
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
return RedirectToAction("Login");
}
Please check this Link There are many way to clear cache, so that back button will not work after logout.

How do I know which user's session id has been expired (and which users are online?)

I am developing an online chess game. After a user presses the login button, I save userid in a session variable:
Session["userID"] = userId.Text;
After assigning the variable, the user is transferred to another page.
There is a possibility more then one user is online at a time. Let say three user are online at a time and in session variable one user contain "1" userId, next contain "2" and so on.
If one of the user's Session Id expires for some reason, how do I know which user's session expired?
The reason is I want to show the other users that this particular user is not online anymore.
How do I know which user session variable expired?
You can subscribe to the SessionStateModule.End event:
public class KyuApplication : System.Web.HttpApplication
{
public override void Init()
{
SessionStateModule session = Modules["Session"] as SessionStateModule;
if (session != null)
{
session.Start += new EventHandler(Session_Start);
session.End += new EventHandler(Session_End);
}
}
private void Session_Start(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine("Session_Start");
}
private void Session_End(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine("Session_End");
}
}
Example from: http://johnllao.wordpress.com/2009/06/05/session_start-and-session_end-event-from-custom-httpapplication/
The reason is I want to show the other users that this particular user is not online anymore.
You approach is unnecessary. The Asp.Net membership framework provides this functionality for you so you don't have to build it yourself. You can use MembershipUser.IsOnline to do this for you.
Example from MSDN:
MembershipUserCollection users;
public void Page_Load()
{
users = Membership.GetAllUsers();
if (!IsPostBack)
{
// Bind users to ListBox.
UsersListBox.DataSource = users;
UsersListBox.DataBind();
}
// If a user is selected, show the properties for the selected user.
if (UsersListBox.SelectedItem != null)
{
MembershipUser u = users[UsersListBox.SelectedItem.Value];
EmailLabel.Text = u.Email;
IsOnlineLabel.Text = u.IsOnline.ToString();
LastLoginDateLabel.Text = u.LastLoginDate.ToString();
CreationDateLabel.Text = u.CreationDate.ToString();
LastActivityDateLabel.Text = u.LastActivityDate.ToString();
}
}
Here are some additional blog posts that discuss this in more detail and describe how to set it up:
http://dotnetslackers.com/articles/aspnet/tracking-user-activity.aspx
http://blog.dreamlabsolutions.com/post/2009/07/13/ASPNET-Membership-Show-list-of-users-online.aspx
Session data is meant to be private to the user and is not meant to be accessible to the rest of your application (that is, outside the user's context). That means that doing what you want using the session is going to be hard and awkward.
A better alternative would be to track user activity in a separate datastructure and keep that in the web server's memory (using a static variable or the System.Web.Caching namespace) or in the database.
For every user you can save session information in remote storage (database for example) with expiration date (that must be MORE than the session expiration date from application configuration) and userID binding and after user is making some action in your application you can change the expiration date by adding some value. So that in this case you always have the list of not expired sessions, controled by you.
With Session variable - you can see session information just about the current request from the client. So that using just this variable you sure can't see other users' sessions, that would be just unsecure.
You can use the SessionStateModule.End Event to catch that.

Loss of session and application ended randomly?

I have sessions recording a user's log in information but it gets lost due to my application ending.
Running my code from local host i have no issues, but now that i have lunched the site live i lose the session very quickly with in minutes.
I decided to log the Golbal.asax file and record when a session is started and ended and when my application starts and ends and if there are any application errors.
When a user navigates thought the website the session is checked if its null, if the session is not null i register hidden fields for that page to use my session values, but if the sessions are null i abandon them and redirect to my login page.
Here is what my log has shown me:
[11:52:25] Application has started
[11:52:25] Session has started
[11:52:35] Use session
[11:52:45] Use session
[11:52:54] Use session
[11:52:59] Use session
[11:53:5 ] Use session
[11:53:10] Use session
[11:53:15] Use session
[11:53:18] Session has ended
[11:53:18] Application has ended
[11:53:22] Application has started
[11:53:23] Session has started
[11:53:23] Abandon Session
[11:53:23] Session has ended
[11:53:23] Session has started
I navigated around my site with 7 clicks on the same hyper link basically just refreshing the page i was on, but for an unknown reason the session was lost and application was ended. As you can see from the log, this was all within a minute.
When a navigation link is clicked this is the code to check the session.
protected override void OnInit(EventArgs e)
{
LogClass Log = new LogClass();
if (this.Session != null && this.Session.Count > 0)
{
Log.Logger("Use session");
string email = (string)this.Session["Email"];
int practiceId = (int)this.Session["PracticeId"];
int practitionerId = (int)this.Session["PractitionerId"];
this.ClientScript.RegisterHiddenField("loggedInUserName", email);
this.ClientScript.RegisterHiddenField("practiceId", practiceId.ToString());
this.ClientScript.RegisterHiddenField("practitionerId", practitionerId.ToString());
}
else
{
Log.Logger("Abandon Session");
this.Session.Abandon();
Response.Cookies.Add(new HttpCookie("ASP.NET_SessionId", ""));
Response.Redirect("~/Default.aspx");
}
base.OnInit(e);
}
What could be causing my session to get lost so quickly, and why is the just a problem when hosted live and not a problem from local host?
What causes the application to end, since i have no application errors logged?

ASP.NET sessionID will not update

I click on refresh button which should restart session:
protected void btnRefresh_Click(object sender, EventArgs e)
{
HttpContext.Current.Session.Abandon();
HttpCookie mycookie = new HttpCookie("ASP.NET_SessionId");
mycookie.Expires = DateTime.Now.AddDays(-1);
Response.Cookies.Add(mycookie);
LblSessionID.Text = HttpContext.Current.Session.SessionID+
" test btnRefresh_Click";
LblIsNewSession.Text = Session.IsNewSession.ToString();
}
But when the button is clicked, the SessionID value in LblSessionID still displays the old value but another label LblIsNewSession will show it as true for IsNewSession. The LblSessionID will then reflect the actual SessionID value when I use asp.net control (like dropdown) that has autopostback="true" and from there SessionID sticks around.
I do use global.asax
Any idea why LblSessionID isn't behaving as it should and is waiting for next postback to start reflecting actual value?
When I launch the web application, the problem is the same - LblSessionID show different value and then change after first postback and stays the same from there.
That's the way it works - If you Abandon the session it won't reflect that until the next Request. It makes sense if you think about it...
Say you have a user that accesses your site and gets a Session ID of 123 (not reflective of an actual value, I know). When you click your button to get a new Session ID, the user's request is from the old Session, and that is the value that is reflected during that Request. Once the session is reset (or abandoned or whatever), the user gets a new Session ID of 321 and subsequent Request's will then reflect that new session ID.
SessionId is not reliable unless you actually store something (anything) in the session.
try
Session.RemoveAll();
Session.Clear();
It is not your code, it is a documented behavior:
"The Abandon method sets a flag in the session state object that indicates that the session state should be abandoned. The flag is examined at the end of the page request. Therefore, the user can still use session objects after you call the Abandon method. As soon as the page processing is completed, the session is removed."
(source: http://support.microsoft.com/kb/899918)
The Abandon() method flags the session collection for clearing at the end of the request, it does not actually clear it immediately.
You can either call the RemoveAll() or Clear() methods for instant deletion of the objects, or issue a Response.Redirect call to the page itself and re-test for the existence of the data.

How can I handle forms authentication timeout exceptions in ASP.NET?

If the session has expired and the user clicks on a link to another webform, the asp.net authentication automatically redirect the user to the login page.
However, there are cases when the user does not click on links to other webforms. For example: edit link in gridviews, when using AutoCompleteExtender with textboxes and the application attempts to get the information, and basically, in every case when a postback is done and the event is not automatically handled by the asp.net authentication.
What is the best way to handle these exceptions?
UPDATE: I have just modified the question title: forms authentication timeout, instead of the initial session timeout. Thanks for making me aware of this difference.
UPDATE: I have just created a new question with the specific problem I am facing: How to handle exception due to expired authentication ticket using UpdatePanel?. Surprisingly, I have not found much information about it. I would really appreciate your help.
This is why many systems include timers on the page to give approximate timeout times. This is tough with interactive pages. You really need to hook ajax functions and look at the return status code, which is a bit difficult.
One alternative is to use code based on the following which runs early in the page lifecycle and perform an ajax redirect to a login page. Otherwise you are stuck trying to intercept the return code from ajax and in asp.net where the ajax is done 'for you' (ie not a more manual method like jQuery) you lose this ease of detection.
http://www.eggheadcafe.com/tutorials/aspnet/7262426f-3c65-4c90-b49c-106470f1d22a/build-an-aspnet-session-timeout-redirect-control.aspx
for a quick hack you can try it directly in pre_init
http://forums.asp.net/t/1193501.aspx
Edit
what is wanted are for forms auth timeouts, not session timeouts. Forms auth timeouts operate on a different scale than session timeouts. Session timeouts update with every request. Forms auth tickets aren't actually updated until half of the time goes by. So if you have timeouts set to an hour and send in one request 25 minutes into it, the session is reset to an hour timeout, the forms auth ticket isnt touched and expires in 35 minutes! To work around this, sync up the session timeout and the forms auth ticket. This way you can still just check session timeouts. If you don't like this then still - do the below and sync up the timeouts and then parse the auth ticket and read its timeout. You can do that using FormsAuthentication.Decrypt - see:
Read form authentication cookie from asp.net code behind
Note that this code requires that upon login you set some session value - in this case its "UniqueUserId". Also change the login page path below to fit yours.
protected void Application_PreRequestHandlerExecute(object sender, EventArgs e)
{
//Only access session state if it is available
if (Context.Handler is IRequiresSessionState || Context.Handler is IReadOnlySessionState)
{
//If we are authenticated AND we dont have a session here.. redirect to login page.
HttpCookie authenticationCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
if (authenticationCookie != null)
{
FormsAuthenticationTicket authenticationTicket = FormsAuthentication.Decrypt(authenticationCookie.Value);
if (!authenticationTicket.Expired)
{
if (Session["UniqueUserId"] == null)
{
//This means for some reason the session expired before the authentication ticket. Force a login.
FormsAuthentication.SignOut();
Response.Redirect("Login.aspx", true);
return;
}
}
}
}
}
If you're using Forms Authentication, the user will be redirected to the login page when the Forms Authentication ticket expires, which is not the same as the Session expiring.
You could consider increasing the Forms Authentication timeout if appropriate. Even to the extent of using a persistent cookie. But if it does expire, there's no real alternative to redirecting to the login page - anything else would be insecure.
One way to deal with Session timeouts is to use Session as a cache - and persist anything important to a backing store such as a database. Then check before accessing anything in Session and refresh if necessary:
MyType MyObject
{
get
{
MyType myObject = Session["MySessionKey"] as MyType
if (myObject == null)
{
myObject = ... get data from a backing store
Session["MySessionKey"] = myObject;
}
return myObject;
}
set
{
Session["MySessionKey"] = value;
... and persist it to backing store if appropriate
}
}
If you're using a master page or a base page, I would add some logic to one of the events in the page lifecycle to check whether the session is new:
protected void Page_Load(object sender, EventArgs e)
{
if (Session.IsNewSession)
{
//do whatever you need to do
}
}

Categories