Tuesday, April 26, 2011

Detect browser closing through clicks on the [X] button

I had been searching through the internet to find out how to control this issue: You have a web application where you validate every user that logs in, if somebody tries to log in from another place with the same user name, he should be denied access because the user is at the system right at that moment.
Well, the way I'm controlling this, is using a table where I put all the users� info. I�ll make this simple. Look at the following example:
Collapse
Table : employee
-------------------
username
password
active
Notice that if the user logs in the application, the field "active" will turn to 1� if the user logs off, the field will turn to 0.
Well ... I have this web application where I have a button to sign out. When I press the button, it invokes a function to update my database to turn �active�=0, but the problem is what if I press the X button of the navigator? I mean, there�s no way to detect using C#, how to catch when I close the browser in order to update the database, right? Everyone told me that the event onUnload (C#) works for detecting it� wrong! This event is not triggered when I close the window but it does when I browse another web page. So it doesn't help me. Others told me that Global.Asax catches a window closing with Session_End.. Wrong! Global.Asax works only when you tell the application to end or when the session expires � Believe me.. I tried a lot of things�
Well I guess I have found a solution to this problem� I took a long time searching though the internet looking for something until I got this link and based on the answer provided in that link, I decided to do this. I have Login.aspx, RETURN.aspx (it has three pages, too, left and principal, it's a frames page�) and the spyWin.aspx , (special thanks to PE_CF_DEV from experts-exchange for the code, I just took your code and mixed it with C#). Work with two session variables, one to save the user login (Session[�USER�]) and the other to check if it's the right moment to update the database (Session[�RETURN�]).
  1. In your login page �login.aspx, you have to put this in the LOAD event:
    Collapse
    if ( Convert.ToString(Session["USER"]).Length > 0 )
    {
        if (Session["RETURN"]!=null)
        {
            if ( Convert.ToInt32(Session["RETURN"]) == 1)
            {
                Session["RETURN"] = 0;
                �<Code to reset database>�
            }
            else
            {
                Response.Redirect("RETURN.aspx",false); 
            }
        }
    }
    This will first check if I had logged in recently, if the session is still alive and is trying to enter at Login.aspx, it will be redirected to RETURN.aspx.
  2. Put this code in the pressed event of the button to log out (this button is located in the left frame):
    Collapse
    Session.Abandon(); 
    Response.Write("<script>javascript: parent.opener=''; " + 
                                    "parent.close();</script>");
    The first line closes the session, this is caught by the event Session_end of GLOBAL.ASAX.
    Collapse
    protected void Session_End(Object sender, EventArgs e)
    {
        if ( Convert.ToString(Session["USER"]).Length > 0 )
        {
            <� Your code to update database>
            Session["USER"] = null;
        }
    }
    The second one, invokes a JavaScript event to close the window. Usually the browser detects when you close it, it sends you a message (message �do you want to close this window?�). The next point will solve this so that no message window appears.
  3. Put this in the LOAD event of RETURN.aspx (not the pages that form the frames page, I mean, not the left, top, or the principal page).
    Collapse
    if (Session["USER"]==null)
    {
        Response.Redirect("Login.aspx",false);
    }
    else { Session["RETURN"] = 0; }
    This will be validated if there's still a user with an active session. I�ll explain a little later, the use of Session["RETURN"].
    At the moment, I can only say that this session variable is initialized.
  4. Put this in the HTML section (in the <HEAD> ) of Index.aspx ( not the pages that form the frames page, I mean, not the left, top, or the principal page).
    Collapse
    <script language="javascript">
    function launch_spyWin() 
    {
        spyWin = open('spyWin.aspx','spyWin',
           'width=100,height=100,left=2000,top=0,status=0');
        spyWin.blur();
    }
    onunload = launch_spyWin;
    </script>
    This will solve the point explained in step 2). My code is based on the code from PE_CF_DEV.
  5. With JavaScript we know that the event �onUnload� will run the function regardless of the page being closed or the user navigating to another page. OK, now write this in the LOAD event of spyWin.aspx.
    Collapse
    if (Convert.ToInt32(Session["RETURN"])==0)
    {
        Session["RETURN"] = 1 ;
        
        string script = "<script type='text/javascript' " + 
                "language="'javascript'"> " +
                " function check_opener() { " +
                " if (opener && opener.closed){ " +
                " parent.opener=''; " +
                " parent.close(); " +
                " window.open('Login.aspx') " +
                " } " +
                " else{ " +
                " parent.opener=''; " +
                " parent.close(); " +
                " } " +
                "} " +
                " onload = function() { " +
                " self.blur(); " +
                " setTimeout('check_opener()',0); " +
                " } " +
                " </script>";
        this.Controls.Add(new LiteralControl(script));
        
    }
    else
    {
        Session["RETURN"] = 0 ;
    }
    This spyWindow is a non-visible popup window that will be triggered when the main window is closed. When I change Session["RETURN"] = 1, the Login.aspx catches this variable and then updates the database (the same function of Session_End of Global.asax)..
Problem solved! Now my life is easier...
Hope this helps someone�

No comments:

Post a Comment