Sunday, December 12, 2004

 

Check For Expired Cookies in OnInit

I am using a session state to store a UserID. I am initializing the value after the user logs in via Forms Authentication. Once logged in this UserID is stored in a session variable which I access throughout the site. This method worked fine until I started debugging. Whenever I compiled the site, the session state would be lost along with all of the session variables, setting the UserID to null.

Using Forms Authentication sets an authentication cookie that does not expire after a re-compile of the project. I would not be forwarded to the login page. But the page I was in would complain that the session variable was null. I would then have to go back to the login page and re-login so the UserID session variable would be initialized again. As you can imagine, this can get really annoying fast.

From an end user's perspective it was even worse. If the session expired, the user would be confused by an error message indicating that their session timed out, and once again, would not be prompted to re-login.

The Solution

To solve this problem for the end users and make debugging less painful for me, I would check if the UserID session variable had expired before processing the rest of the page. If the variable had expired, I would forward the user to a page that would tell them in plain english that their session had expired and request that they login again.

I decided to add the null session variable check to a User Control that was registered on all of the affected pages. I initially added the check for the session variable to the PageLoad event handler. Like so:

private void Page_Load()
{
If (Session["UserID"] == null)
{
Response.Redirect("SessionExpired.aspx");
}
}

I compiled the application and logged in. After re-compiling the application I clicked the refresh button on my browser, fully expecting to be redirected to the appropriate page after failing the null session check. Instead, I received the same ugly error message telling me that the session variable I was requesting in the .aspx page was null. Duh! I already knew that.

OK, what could be the problem? I decided to put a break point on the Session request in both the .aspx page and the registered user control. Both requests were occurring during the PageLoad event handler, but I had a hunch that the .aspx page's PageLoad event was firing before the User Control's. I pushed F5. I then clicked the "Refresh" button on the browser. Sure enough, the .aspx pages PageLoad event was firing before the User Control's PageLoad event would fire.

How can I get around this? I decided to try and find a User Control Event that fired before the PageLoad event, but far enough along in process that I could access the Session variables.

I Googled and found a helpful article by Paul Wilson over at ASP Alliance titled Page Events : Order and Postback. The article explained, in the author's own words,


"the complete lifecycle of ASP.NET Pages, including the postback sequence, and
explains which method or event to use in common scenarios. "

Perfect!

I was able to determine that the OnInit Event is where I should be. It fires before the PageLoad event, and allows me to access the Session Variables. I added the appropriate code to the existing OnInit event handler, like so:

override protected void OnInit(EventArgs e)
{
//
// CODEGEN: This call is required by the ASP.NET Web Form Designer.
//
InitializeComponent();
if (Session["UserID"] == null)
Response.Redirect("SessionExpired.aspx");
base.OnInit(e);
}

Works great!

Can anyone think of a better way of handling this scenario?



Comments:
Why don't you just use both? If you have all of your pages secured through forms authentication, you can get the UserID from that.

if ( Session["UserID"] == null )
{
Session["UserID"] = GetUserID( User.Identity.Name );
}

That is assuming you have a method called GetUserID that takes that username from the forms authentication ticket and can determine the user ID. That way you won't have problems when the Session times out on your server.

If the User.Identity.Name is not present, then the FormsAuthentication ticket would not be present and the framework would redirect them automatically to the login page where the UserID would be set by your existing code.

HTH,
bill
theman@fdrsucks.com
 
I think the problem is related to your session state getting lost after redirecting to a new page. The link below might be helpful.

Don't redirect after setting a Session variable (or do it right)
 
The first comment suggesting recreating the session from the identity is nice, but won't work if there is any extra stuff in the session. UserData is another solution that I've seen other blogs suggest, but seems kind of hackish to me. Your solution is great, but I do think there can be a slight improvement to your code:


if (Session.IsNewSession && Request.IsAuthenticated)
{
FormsAuthentication.SignOut();
Response.Redirect("Default.aspx");
}


That way, it's not dependant on which part of the session doesn't exist, and by signing out, you fix the problem of the unexpired authentication.
 
Post a Comment

Links to this post:

Create a Link



<< Home
Content copyright ©2003-2006 Tod Birdsall