Archive for June, 2008

Handling Session Timeout

June 29, 2008

I was asked to elegantly handle Session Timeout in our application and was directed to the linked article at Nikhil Kolthari’s blog .

Nikhil provides two fully-coded examples of handling Session Timeout. The second example works brilliantly, the first example does not work at all.

This Works

Here is Nikhil’s Session Expiry detection code that works:


protected override void OnInit(EventArgs e)
{
base.OnInit(e);
if (Context.Session != null)
{
//check whether a new session was generated
if (Session.IsNewSession)
{
//check whether a cookies had already been associated with this request
HttpCookie sessionCookie = Request.Cookies["ASP.NET_SessionId"];
if (sessionCookie != null)
{
string sessionValue = sessionCookie.Value;
if (!string.IsNullOrEmpty(sessionValue))
{
// we have session timeout condition!
// Response.Redirect("SessionTimeout.htm");
Session["IsSessionTimeOut"] = true;
}
}
}
}
}

Why it works

The first time you put anything into Session State, ASP.NET creates the Session cookie called ASP.NET_SessionId. When Session Timeout occurs the ASP.NET_SessionId cookie is deleted BUT the Session itself is not. Provided the user does not close their browser, ASP.NET will recycle the Session but using the same SessionId as soon as the user sits down at their browser and starts using the expired Session again. Session.IsNewSession is true for the recycled Session, the SessionId still belongs to the same user (they didn’t close their browser) but the State within that Session, which is contained in the cookie ASP.NET_SessionId, has expired and is hence null.

That’s why checking for Session.IsNewSession and ASP.NET_SessionId = false detects an expired session.

NB: As Nikhil says, the above code depends on having Session_Start wired up in Global.asax.

This Doesn’t Work

Here is Nikhil’s example which doesn’t work.


First, in Global.asax, create your own GUID and put it in the session object,

void Session_Start(object sender, EventArgs e)
{
// Code that runs when a new session is started
Session["CustomSessionId"] = Guid.NewGuid();
}

Second, BasePage.cs which would have inherited Page, in PageLoad() event, check whether the Session["CustomSessionId"] == null, if it IS null, it means that the session was timed-out and AspNet runtime cleared it out.

if( Session["CustomSessionId"] == null)
{
Response.Redirect("TimeoutPage.htm");
}

Why It Doesn’t Work

On Session timeout, Session State is discarded. As soon as the user becomes active in the timed-out Session, the SessionId is recycled, Session_Start is invoked and “CustomSessionId” will be re-initialised. This means “CustomSessionId” will never be null and thus the Session timeout condition in BasePage.cs will never be true.

Use the other example that Nikhil provides. It works. Thanks Nikhil for the tip. You saved me heaps of work!

Advertisements

Enter Key Always Causes Postback

June 29, 2008

Flamin’ annoying.

On this one particular page the enter key would trigger a postback on an Image Button OnClick event, needlessly bringing up our beautiful UserSearch screen over and over and over again.

I hunted though the source code like a Victorian-era botanist on a first-time trip to Patagonia, digging for traces of rogue Javascript, untamed Event Handlers and variegated _DOPOSTBACK calls but found none.

Thoroughly stumped, I reached for Google and ended up at Matt Webster’s blog. His thread (sorry I lost the URL) was stocked with more clues than a warehouse full of Agatha Christie paperbacks and, while not providing the answer exactly, it gave me the gist that the Enter Key has a magnetic attraction for the first ‘Submit’ control it can find – in our case the ultra-assertive Image Button that invoked the UserSearch Control with jihadist fervour.

My solution was a trademark brutal hack.

I just put ANOTHER submit button immediately prior to the Image Button and trapped OnClientClick to return false. So my markup ended up looking like this:


asp:LinkButton ID="hackyDefaultButton" OnClientClick="return false; Visible="false"
asp:ImageButton ID="userSearchButton" OnClick="InvokeUserSearch"

So the Enter Key finds the first submit button on the page which is now the hacky default button and does nothing, unless the Page focus is on the ImageButton in which case it fires InvokeUserSearch.

Brutal hacks. Love ’em.

RFI

Is the above the worst brutal hack you’ve seen ?

Please feel free to rate/flame my hack, but in the interests of constructive criticism, tell me what I should have done better.

Addendum 29-June-2008

This article by 4GuysFromRolla clearly explains the issue and told me that single-line textboxes will almost always cause a submit to be executed on the first button on the HTML form on the Web Page depending on how your browser implements the HTML 2.0 standard.

In the case of IE, a Web Form with more than one single-line Textbox and a submit button will always generate a postback on the first submit button in the form (unless you have done something explicit to modify that behaviour e.g set a DefaultButton on the form).

AND

They solved the issue in exactly the same way I did !!!
Maybe I’m a genius.