Showing posts with label JavaScript. Show all posts
Showing posts with label JavaScript. Show all posts

Wednesday, October 24, 2012

Kill the session when the browser is closed

In one of my projects, I used Form Authentication to authenticate users against our Intranet domain by using LDAP.  The good things are users don't have to remember another pair of user name and password, and form authentication gives users ability to log out.  Users cannot log out if we use Windows Integrated Authentication.

By design, if users click something which they don't have permission, form authentication will automatically redirect them to the login page, and there users can log in with another account to access the desired resource.  However in some use cases, users don't like this behaviour.  They argue that it's rare that users have 2 accounts in the system.  So if they don't have permission, we don't have to redirect them to the login page.  We just need to display some messages indicating they need an admin to reassign them the proper permission.  Here I just have a workaround when users are redirected to the login page, I will display some information on the login page to explain why they are showed the login page.

Another user requirement is users want to kill the session and log out when the browser is shut down.  This requirement looks simple but It took me a long time to work on it.  Even worse is so far I haven't gotten the proper way to resolve the problem.  But I did get some workarounds in this stage.

When I searched from the internet, most people said you couldn't log out automatically. This is true in that the session is stored in the server, when users close the browser, the browser normally just closes and won't send a message to the server.  So the server never knows the client is already gone.

But when you go to some bank websites, closing browser will log you out immediately.  When you go to the same site again, the site always asks for your credentials.  I don't know how exactly they are doing.  However, I think they might use their own login mechanism.  Users are always directed to the login page when users first open the website.  When login page opens, the website always clear the old session and old credentials, so users have to enter their account again.  Since in the middle, they won't be redirected to the login page, so this clearing won't bring trouble.

I referenced this blog and this discussion and this discussion to implement my workaround.

First created the Exit.aspx page.  In the page load method, do the following:

    protected void Page_Load(object sender, EventArgs e)
    {
        FormsAuthentication.SignOut();
        Session.Abandon();
       
        // clear authentication cookie
        HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, "");
        cookie.Expires = DateTime.Now.AddYears(-1);
        Response.Cookies.Add(cookie);

        FormsAuthentication.RedirectToLoginPage();
    }

The code kills the session and logs out the user.  I put the code in the page load event handler so this page will never be displayed.

Then in the normal pages add the following javascript code.  Since I have a master page for all my pages, I can put this code in my master page so every page will be affected.

<script type="text/javascript" >
    var closeTab = false;
    window.onbeforeunload = checkBrowserBefore;
    window.onunload = checkBrowserUnload;

    function checkBrowserBefore() {
        if (window.event.clientY <= 0) {
            closeTab = true;
            return "Do you leave the application or stay?";
        }
        else
            closeTab = false;
    }
    function checkBrowserUnload() {
        if (closeTab)
            window.location.href = "../Exit.aspx";
    }
</script>

Notice here I check 2 events onbeforeunload and onunload.  When users close the browser tab or browser, the onbeforeunload will fire.  In IE a message box will pop up asking user to confirm the closing.  If user clicks Yes, or in some new IE versions users choose Leave the page, the onunload will fire.  Otherwise the onunload will not fire.  That's the reason we have to check both events.

Again we should remember this is just a workaround and not guaranteed.  This workaound only works in IE, but not even in all IE versions.  In IE7, it works when users close either the IE tab or the entire IE browser.  But in IE9, it works when users close the IE tab, but not working when users close the  IE browser.  I haven't tested on other IE versions or other browsers.

Also it is not working when users kill the browser process in task manager or use Alt + F4 to close it.

Sunday, January 3, 2010

Silverlight and JavaScript interaction

In Silverlight business applications, we may need to pass data to the Silverlight control.  If the volume of data is not big, we can consider using Silverlight HTML Bridge to communicate between JavaScript and Silverlight. This post summarizes how to call JavaScript from Silverlight and vice versa.

Silverlight HTML Bridge is the technology that enables to call 
JavaScript from Silverlight managed code and call Silverlight managed code from JavaScript.  The following example will use some simple code to demonstrate the 2 parts and point out some usual difficulties developers may encounter.

Call Silverlight from JavaScript

In the test.aspx file, I have the following form: 
  
    <form id="form1" runat="server" style="height:100%;">
        <asp:ScriptManager ID="ScriptManager1" runat="server">                          </asp:ScriptManager>
        <div>
            <input type="button" value="Start Silverlight" onclick="startSilverlight();" />
            <input type="hidden" id="hiddenString" value="0.85,0.78,0.10,0.12,0.90" />
        </div>
        <div style="height:100%;">
            <asp:Silverlight ID="Xaml1" Visible="true" runat="server" Source="~/ClientBin/SilverlightTest.xap"                             MinimumVersion="2.0.31005.0" Width="100%" Height="100%" />
        </div>

    </form>

And I also have the following JavaScript in the same page: 
<script type="text/javascript" language="javascript">
    function startSilverlight() {
        var plugin = document.getElementById("Xaml1");
        if (plugin == null) {
            alert("xaml1 is null");
            return;
       
}
        var strControl = document.getElementById("hiddenString");
       
var str = strControl.value;
        plugin.Content.Page.StartShow(str);
    }

</script>

In Silverlight, the code-behind file contains the following code:
    [ScriptableType]
    public partial class Page : UserControl
    {
        public Page()
        {
            InitializeComponent();
            HtmlPage.RegisterScriptableObject("Page", this);
        } 
        [ScriptableMember]
        public void StartShow(string data)
        {
            char[] charSeparators = { ',' };
            string[] result;
            result = data.Split(charSeparators, StringSplitOptions.RemoveEmptyEntries);
            float values[] = new float[result.Length];
            int i = 0;
            foreach (var str in result)
            {
                values[i++] = float.Parse(str);
            } 
            UpdateLayout(values);
        }
    }

When users click the button on test.aspx page, the hidden text can be passed to Silverlight.

Call JavaScript from Silverlight

In test.aspx, I added
<script type="text/javascript" language="javascript">
    function getSilverlightValue(text) {
        alert(text);
    }

</script>

In Silverlight code-behind file, use HtmlPage to call the function: 
    HtmlPage.Window.Invoke("getSilverlightValue", "A test string");

Final Words

This is all the things related with how JavaScript and Silverlight interact. However, what I want to point out here is this convenient method may have some performance issues when you want to pass high volume of data to Silverlight.  In my real project, I passed over 30 Mega pure data to Silverlight and I needed to parse the data, so the data needed over 10 seconds to be fully displayed.  Some users may not want this experience.  If that's the case, you may seek help from WCF to retrieve data in an asynchronous way.