views:

68

answers:

5

Alternate Title: How to redirect on session timeout

FINAL SOLUTION: Credit to: Robin Day (Although I tested Ben's solution and it also works and the other two solutions are also both good solutions)

I got rid of the basepage that I had originally.

Put this in the Session_Start of Global.asax

void Session_Start(object sender, EventArgs e) 
{
    string cookie = Request.Headers["Cookie"];
    // Code that runs when a new session is started
    if ((null != cookie) && (cookie.IndexOf("ASP.NET_SessionId") >= 0))//&& !Request.QueryString["timeout"].ToString().Equals("yes"))  
    {
        if(Request.QueryString["timeout"] == null || !Request.QueryString["timeout"].ToString().Equals("yes"))
            Response.Redirect("Default.aspx?timeout=yes");
    }
}

Put this on the Defualt.aspx page:

 if (!IsPostBack)
    {
        if (Request.QueryString["timeout"] != null && Request.QueryString["timeout"].ToString().Equals("yes"))
        {
            Response.Write("<script>" +
               "alert('Your Session has Timedout due to Inactivity');" +
               "location.href='Default.aspx';" +
               "</script>");
        }
    }

This solution works even when the timeout occurs on the Default.aspx page


END SOLUTION

I have a base page that checks for session timeout. (thats all it does). I want to redirect to the home page if there is a session timeout. However, the home page also inherits from this base page.

I'm not sure if i'm explaining this well:

Step 1: One of my pages loads

Step 2: It sits for more than 20 minutes(this would cause session timeout).

Step 3: I click on something that causes poastback

Step 4: Basepage detects timeout and redirects to default.aspx

Step 5: As default.aspx loads, the basepage detects that there is still a timeout and once again tries to redirect to default.aspx. Step 6: Repeat step 5

The bold is the undesired effect...

This is the basepage code.

using System;  
using System.Web.UI;   
public class SessionCheck : System.Web.UI.Page  
{   
public SessionCheck()  {}  

override protected void OnInit(EventArgs e)  
{  
    base.OnInit(e);  

    if (Context.Session != null)  
         {  
             //check the IsNewSession value, this will tell us if the session has been reset.  
             //IsNewSession will also let us know if the users session has timed out  
             if (Session.IsNewSession)  
             {  
                //now we know it's a new session, so we check to see if a cookie is present  
                 string cookie = Request.Headers["Cookie"];  
                 //now we determine if there is a cookie does it contains what we're looking for 
                 if ((null != cookie) && (cookie.IndexOf("ASP.NET_SessionId") >= 0))  
                 {  
                     //since it's a new session but a ASP.Net cookie exist we know  
                     //the session has expired so we need to redirect them  
                     Response.Redirect("Default.aspx?timeout=yes&success=no");  
                 }  
             }  
         }  
     }  
} 

Thanks!!!

(If you need further clarification please ask)

Note: I know that if I redirect to a page that does not inherit from this basepage it would fix the problem. But i don't like this solution.

+1  A: 

Can you use the event Session_OnStart within the Global.asax?

This will be fired once whenever a new session begins. You can do your redirect in there.

The key I guess though is that you only redirect to the home page if you're not already on it. You can do this by just checking the URL in the Request object.

Robin Day
I like the first idea a LOT! can you explain further (idk what Global.asax is...) but if I am on the homepage and the session timesout i want the redirect because I want the querystring to say timeout = true.
kralco626
Is this an ASP.Net Web Application Project? In the root of your project there should be a file called `Global.asax`. This should have a corresponding code behind file. If it is not there then you can right click on the project and choose `Add New Item` and pick `Global Application Class`
Robin Day
Sweet. I got the global.asax file. But if I do something on the session_start event wont that also execute when I load the site for the first time and a new session is created?
kralco626
You can do the same cookie check as before to check if there was a pre-existing session. The key to using this event is that it will only fire once. Therefore any re-direct you do will not cause it to re-fire.
Robin Day
I got an error doing a redirect in the Session_End. I read that it is not possable to do redirect in session_end: http://forums.asp.net/p/1137344/1834495.aspx (second post)
kralco626
I wouldn't use the Session_End event. It always seems to produce unexpected results. A session can end long after a user has closed their browser. Stick to using Session_Start and just use your Cookie check as in your existing code.
Robin Day
So your telling me I can do Response.Redirect from Session_start?
kralco626
See top for the solution I used. THANKS!
kralco626
+1  A: 

Create a common base page that contains all things you want to have both in your home page and in other pages.

Than, you inherits from this your home page and another base page (say SessionCheck ) in which to put your session expiration logic. All your pages but home have than to inherits from SessionCheck page.

public class BasePage: System.Web.UI.Page //(this contains all things shared between all pages) public class SessionCheck : BasePage //(your session loginc in this class) public class Home : BasePage

Andrea Parodi
Kinda get you. Your basiclaly saying don't have the homepage inherit from the basepage that does the session check
kralco626
Yes. It's better to inherit from a common, base page (if other code have to be shared between home and other pages)
Andrea Parodi
Ya I thought of this. I was really hoping for a solution that would check for timeouts on any page including the home page.
kralco626
In this case, you can not just check request params for the parameter "timeout" you pass to the url in case of redirection? If == "yes", skip the session check
Andrea Parodi
ya but i thought the query strings were not created yet in the init function? I guess it would be though... idk i'll try it
kralco626
No, you're right: it's not yet created. But why you want to check session expiring in home page, just to redirect to same page?
Andrea Parodi
Yes, redirect to the same page with the querystring set to timeout=yes so in the default page i can say if(timeout=yes) then alert(...) Because I cannot call the vbScript from the basepage. (at least I tried and was unsuccessfull) Edit: the alert is a VbScript not javascript
kralco626
couldn'y you redirect to another page used only to display the alert? In this page, you don't do the check. You could inherits this page from home and re-override OnInit
Andrea Parodi
Ya I could redirect to Timout.aspx and in page load have: myalert("page timedout"); and then on clicking OK do Responce.Redirect("Default.aspx")
kralco626
or can i call javascript from the basepage? I could have the timeout.aspx page be the popup itself called from the basepage, but idk if i can do that.
kralco626
I think it's better to call the js from Timeout.aspx and then redirect
Andrea Parodi
+1  A: 

We had similar situation. We first check if the there's Session Timeout and within that we only redirect if current page is not the Default Login page.

this. __curious_geek
if I am on the homepage and the session timesout i want the redirect because I want the querystring to say timeout = true. Although maybe it doesn't matter all that much. I guess it's not a big deal if I don't know it's a timeout on the default page...
kralco626
To us, this was the simplest solution and we found that everything else was overkill for this small little problem. so we did it this way. We just did not redirect if it's the same page.
this. __curious_geek
Simply define your criteria where you do and don't want to redirect then act accordingly. E.g. If you set the querystring timeout = true when you redirect and you don't want it to get into an infinite loop then don't redirect if the querystring is already timeout = true
Ben Robinson
Well andrea mentioned that in the comments of that answer, but we didn't think that in the init method the querystring would be accessable...
kralco626
but you can set a flag to determine if redirection should be performed. From the Page_Load, you can check the flag and conditionally redirect.
this. __curious_geek
but page_load happens after init. it never reaches page_load of the default.aspx, it hits the basepages init first
kralco626
so don't perform redirection in init handler.
this. __curious_geek
didn't think of that.
kralco626
+1  A: 

The below will do the trick with your existing code but robin day's sugestion of using global.asax is a better option.

if (Context.Session != null)  
     {  
         //check the IsNewSession value, this will tell us if the session has been reset.  
         //IsNewSession will also let us know if the users session has timed out  
         if (Session.IsNewSession)  
         {  
            //now we know it's a new session, so we check to see if a cookie is present  
             string cookie = Request.Headers["Cookie"];  
             //now we determine if there is a cookie does it contains what we're looking for 
             if ((null != cookie) && (cookie.IndexOf("ASP.NET_SessionId") >= 0))  
             {  
                 //since it's a new session but a ASP.Net cookie exist we know  
                 //the session has expired so we need to redirect them
                 //Only redirect if the current page is NOT Default.aspx
                 if (Request.Path.Substring(Request.Path.LastIndexOf("/")) != "/Default.aspx") 
                 {
                     Response.Redirect("Default.aspx?timeout=yes&success=no");  
                 }
                 else if (Request.QueryString["timeout"] == "yes")
                 {
                     ScriptManager.RegisterStartupScript(this, this.GetType(), "TimeOutScript", "alert('Your session timed out');", true);
                 }
             }  
         }  
     } 

Editing the answer to respond to comments below becuase it is easier than adding more comments:

I did not provide you with a solution to redirect when the session timed out, you simply cannot do that, the session has timed out, there is nothing to redirect. You said "i just wanna know if there was a timeout" and i gave you a solution for that. There is no real way to tell if a user is hitting page x becuase their session has timed out or because they have opened a browser and started a new session, all you know is there is no existing session. If they hit a page they need to be authenticated to view then you can assume the session has timed out because they should not be hitting the page from scratch. But you can't do this on the home page becuase you can't tell the difference between a user who's session timed out on this page and a user who is just hitting the page for the first time. I have updated the code so that for every page other than Default.aspx it will redirect, and if it has redirected to Default.aspx due to a session time out it will pop up a javascript alert.

Ben Robinson
Ya it's looking like this may be the solution. The other two guys mentioned it too... I just feel like it's not the best solution, because what if I wanted to know about a timeout that happened while I was on the default.aspx page?
kralco626
You cannot really know what page a user had last visited when the session timed out, without doing something like storing the last page visited of each user in a database and updating it every time the visit a new page. You can only tell if the the page being visited is starting a new session, if you want to do something other than rediect if the page is Default.aspx then simply add an else to the if statement i added and put your code in there.
Ben Robinson
I don't care what page the timeout happened on, i just wanna know if there was a timeout(on any page, including the default.aspx page)
kralco626
If you add a method `protected void Session_End(object sender, EventArgs e)` to Global ASAX it will execute when a session expires, you can do stuff in there. This will fire whenever a session ends though, not just when it times out, e.g. if you have a log out process the kills the session, it will fire then also.
Ben Robinson
Don't have a logout because there is no log in. site auto authenticated based on your windows login name. This is an internal site on a company network... so that could work... can I call a javascript model alert from that method?
kralco626
Or just redirect and call the popup from the default page like I originally planned. Ya I like that!
kralco626
I tried void Session_End(object sender, EventArgs e) { Response.Redirect("Default.aspx?timeout=yes"); }but after the Session_End executed the Application_Error executed... AND the page did not redirect! whats going on?
kralco626
Well come to find out... your can't do a redirect from Session_End... so this solution will not work
kralco626
Nice Ben, this solution does work, I just decided to go with using the Global.asax because, like you said, its a better way to go about doing things.
kralco626
A: 

Put a property in your base page:

public bool IsDefault { get; set; }

In the PreInit event of your default page:

public void Default_PreInit(object sender, System.EventArgs e)
{
    this.IsDefault = true;
}

Modify your session check:

if (Context.Session != null && !this.IsDefault)
{
    // blibbitty blah blah
}
Joel Etherton
This would not work if I was on a page that timedout and then I tried to navigate to the default page
kralco626
@kralco626 - I'm not sure what you mean. This property setting would only occur in the default page. What exactly wouldn't work?
Joel Etherton
This is how I understand it. I am on page x and I don't do anything for 20 minutes. I click a link to default.aspx. The Preinit method sets this.IsDefault = true. Then the basepage init method will see this and not execute the code.
kralco626