CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Brendan Tompkins [MVP]

Blog First. Ask Questions Later.

End User Sessions When the Browser Closes With Remote Scripting

I literally stumbled across this solution while creating the WSMQ Instant Messenger demo that I posed about last week.   My problem was that I needed a way to log users out of the chat application when they closed their browser window.  Since I was storing my list of users in the application, they'd hang around indefinitely unless I manually pulled them out, or until the worker process restarted.

Then it occurred to me that this may also work as a mechanism to automatically time out a users session when they close their browser.  On a big website, you could have hundreds of sessions sitting around taking up memory, that aren't being used.  Depending on what you've decided to load the session up with, this could be a resource hit for your web server.  By default, these sessions will timeout after 20 minutes, but with this method, you can time them out as soon as the user closes their browser. 

The solution requires using this Remote Scripting Java Script library from Alvaro Mendez that allows you to call any method on an ASP.NET page from within client-side Java Script.  It also requires that pages in your site inherit from a PageBase class (which is good practice and hopefully you're doing this anyway).

Step 1 - Add the RemoteScripting.cs file to your project

This just has to live somewhere in your project, or in a referenced DLL.  If you have a [Your Namespace].Web project, this would be a good place to put this so that you can re-use it across web applications.

Step 2 - Give RemoteScripting a chance to handle each request

You can do this in a variety of ways, but one sure way is to add the following line of code to your PageBase's OnInit method.  What this will do it let RemoteScripting handle the request if it needs to.  Now, there is a bit of a trade off here, you are adding extra cycles to each request, so you may want to consider the overall payoff here.  It's not much processing if there was no remote method called.

protected override void OnInit(EventArgs e){
  // If it was called invoke the remote method and get back to the client
  RemoteScripting.InvokeMethod(this);
}

Step 3 - Add an EndSession method to your PageBase Class

This will be the remote method that gets called when the browser window is closed.

public void EndSession() {
  // This will call the application session on end method.
 
this.Session.Abandon();
}

Step 4 - Include the rs.js Client Side JavaScript Library on your Pages.

You've got to add the rs.js script which comes with the RemoteScripting to each page.  You could do this in the ASPX code, or pro grammatically in your PageBase.  A good place to do this would be in your OnPreRender method.

Step 5 - Add a JavaScript event handler to your ASPX page's onbeforeunload event.

Unfortunately, the following script only works with IE.  If anyone can figure out how to get it to work with Firefox, that would be awesome.  It at least doesn't cause problems in FireFox, so it should be relatively harmless...

// Wire up the onbefore unload event
window.onbeforeunload = EndSession;

// Close all open chat windows, and call the remote method to logout of the application
function EndSession()
{
  
// Get the real ASPX page name
  
var sPath = window.location.pathname;
  
var sPage = sPath.substring(sPath.lastIndexOf('/') + 1);
   
if(sPage == '') sPage = "Default.aspx";

  
// They're in a  popup window, don't kill the session here!
   
if(window.opener != null) return;

 

   // Only want to run the endsession for IE, no way to tell currently if it's not IE and
  
// the window is closing
  
if(window.event != null) {
    
var abssize = document.body.offsetWidth-30;
    
if (window.event.clientY < 0 && event.clientX >= abssize)  {
           RS.Execute(sPage
, "EndSession");
     }
   }
}

That's it!  Now when someone closes their browser, the remote method should be called, and the session gets killed.  I'd recommend that if you try to do this, you do some debugging to make sure that you have everything wired up correctly, since there's no UI component to this.

Good Luck!

-Brendan



Comments

mdh said:

Great Work, this is exactly what I have been looking for, only I need it it VB.net I have tried to covert but it doesnt seem to work,

could you point me in the right direction...anything I need to pay attention to?

Thanks

send_to_mdh@yahoo.com.au
# November 7, 2005 11:19 PM

Arun said:

This looks great.  But I can't see this running as expected.  When I close the window, the RemoteScripting call is made from the javascript, but when the control reaches OnInit method on the server side, the execution ends.  This may be because of the closure of the window even before the control reached there.  Can someone help me fix this?

You can mail me at arunkumarkvs@gmail.com
# April 11, 2006 10:23 AM

AmalS said:

Good.It is working fine for me.
# April 26, 2006 7:00 AM

Grammar Nots said:

This just keeps bothering me: "Unfortunately, the following script works with IE."  Insert "only" in front of "works" and it suddenly makes much more sense, unless we're disappointed by IE actually functioning.

# September 8, 2006 8:49 AM

Carl Nelson said:

This works great for the "x" button. I modified it to also check for Alt-F4. Unfortunately, I cannot figure out a way to trap File->Close, or right-clicking on the task bar and selecting Close.

To make this work, I added the following script code:

// Track key presses

document.onkeydown = checkKeyCode;

// global variables used by checkKeyCode and checkForBrowserClose functions

var oldKeyCode;

var closingKey;

// what key was pressed?

function checkKeyCode(key)

{

 var keyCode;

 if (window.event)

 {

   keyCode = window.event.keyCode;

 }

 else if (key)

 {

   keyCode = key.which;

 }

 // If the user pressed the Alt key(18) and then F4(115), they are trying to close the browser

 if((keyCode == 115) && (oldKeyCode == 18))

 {

   closingKey = true;

 }

 oldKeyCode = keyCode;

}

I changed this line in your function:

      if (window.event.clientY < 0 && event.clientX >= abssize)  

to this:

     if (((window.event.clientY < 0) && (event.clientX >= absSize)) || (closingKey))

and added this line at the end of your function, before the closing brace, to reset the closingKey flag:

    closingKey = false;

I hope this helps someone, and I hope someone can figure out the File->Close method.

Thanks,

Carl

# October 6, 2006 12:28 AM

Carl Nelson said:

Sorry, I should have written:

if (((window.event.clientY < 0) && (event.clientX >= abssize)) || (closingKey))

(I had changed abssize to absSize).

Thanks,

Carl

# October 6, 2006 12:31 AM

Nick said:

Nice code.  But I am having a problem in my app.  I create temporary directories during execution.  In the EndSession function mentioned above I call Directory.Delete(), right before Session.Abandon(),  to erase them.  However the Delete() works erradictly over a remote connection.  Sometimes it deletes the folders and more often it does not.  Could it have anything to do with garbage collection upon exiting the app?

Any ideas?

Nick

# November 8, 2006 9:12 AM

Nick said:

Nevermind.  I figured it out.  The remote connection I was using was through a vm and for some reason the vm instance of my app does not end the session upon closing of the browser.  It ends after the default 20 mins.  Not sure why this happens with the vm, but whatever.  It works fine otherwise.

Nick

# November 10, 2006 7:29 AM

Harry said:

Great article!  I got this to work on a standard aspx page on IE 7, but I cannot get it to work with a page nested in a master page in IE 6.  Is there any different I need to do?

Thanks in advance,

Harry

# December 11, 2006 11:19 AM

Carl Nelson said:

Hi, Harry.

Works fine for me in IE6. I have the call in my master page, not in a page contained by the master page. Or do you mean a nested master page? I haven't tried it that way; I had too many problems with nested master pages.

# December 15, 2006 10:34 PM

BananaNguyen said:

Good job, this is exactly what i need at current. Thanks.

# June 14, 2007 11:43 PM

Bhanu said:

I have nested master pages and i wrote a web service to call a session.abandon and calling that method from master pages through script manager tag and enablepagemethods true and calling service method as PageMethods.AbandonSession(), The definition of this i gave in web service.

But the problem is Pagemethoda.abandonSession() is not calling my web service method even after giving a service refernce in my script manger tag

# June 19, 2007 7:33 AM

Subburaj.S said:

Hi,

            I have done for all options to close the browser window like alt f4, file>>exit, browser close by calling body unload() but the Firefox raises this event even if call any event in the page like linkbutton onclick event. Awiting for this solution.

Thanks,

Subburaj.S

# July 9, 2007 4:53 PM

Carlos Solis said:

I think its a great code, but a better way to do this is described in the link below

Add to the close window options when in IE7 the user close the tab window.

aspalliance.com/1294_CodeSnip_Handle_Browser_Close_Event_on_the_ServerSide

# August 10, 2007 3:22 PM

Nisar Khan said:

is there a download project?

thanks.

# January 29, 2008 2:51 PM

mkuczara said:

No let someone show me how to handle tab closing (FF and IE7) and i'll be happy.

# January 29, 2008 3:11 PM

leo said:

Working fine, but still there is a bug here..

After pressing Alt+F4, we will get an alert message.. Now click on cancel.. after that refresh the page..

Now alert is raising....

# May 19, 2008 5:12 AM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add

About Brendan Tompkins

Brendan has been programming with .NET since the first public beta and is owner and operator of Port Technology Services, a consultancy company providing .NET application development services to the Maritime industry. In July, 2007, he was awarded the Microsoft MVP award for ASP.NET. He's also a proud co-founder of failed .COM startup Intrinsigo, and has had a hand in the failure of numerous other businesses. He currently runs CodeBetter.Com and Devlicio.us, and lives in Norfolk, Virgina with his wife Tiara and son Ian.

View Brendan's profile on LinkedIn

Check out Devlicio.us!

Our Sponsors

Proudly Partnered With


This Blog

Syndication

News

MVP
Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 License.