Thursday, January 13, 2011

Session Timeout with Warning and jQuery Session Refresh in ASP.Net

ASP.Net applications are written in such a way that after the session times out, the user is also logged out. This is sometimes to secure the application from others accessing the computer, while the real user is away from their desk. If this is the case, it’s nice to let the user know how long they’ve got left before they’re logged out due to inactivity. I got this from This Site Written in Cold Fusion.
I Converted To work in C# and Added Progress Bar With in Message Box.



Download

Summary

- User logs in, session created.
- Session set to time out (e.g. 30 minutes).
- When session times out, the user is logged out.
- Display a countdown so the user knows how long is left.
- Inform the user when they are approaching the limit (e.g. 5 minutes left).
- Let the user know that they’ve been automatically timed out due to inactivity.

Approach taken

Every request to the application will set two cookies:
Date / time the session will expire.
Current server date / time.
Our bit of JavaScript watches these cookies.
Any application activity will update these cookies so we know if a second window has done something and the session timeout refreshed.

sessionTimeout()


This is my first real effort at creating a jQuery plugin. It took a bit more effort wrapping everything up nicely and providing options but I think it was worth it and should make the code easier to include.

   (function($) {
    $.fn.sessionTimeout = function(options) {
        var opts = $.extend({}, $.fn.sessionTimeout.defaults, options);
        var inter = this.data('timer');
        if (inter) {
            clearInterval(inter);
        }

        var info = {
            warned: false,
            expired: false
        };
        processCookie(info, opts);

        this.data('timer', setInterval(cookieCheck, opts.interval, this, info, opts));
        cookieCheck(this, info, opts);
    };

    function processCookie(info, opts) {
        info.serverTime = Date.parse($.fn.sessionTimeout.readCookie(opts.timeCookie));
        info.sessionTime = Date.parse($.fn.sessionTimeout.readCookie(opts.sessCookie));
        info.offset = new Date().getTime() - info.serverTime;
        info.expires = info.sessionTime + info.offset;
        info.duration = Math.floor((info.sessionTime - info.serverTime) / 1000);
    };

    // private
    function cookieCheck(els, info, opts) {
        var sessionTime = Date.parse($.fn.sessionTimeout.readCookie(opts.sessCookie));
        if (sessionTime != info.sessionTime) {
            processCookie(info, opts);
        }
        info.timeLeft = {};
        var ms = info.expires - (new Date().getTime());
        info.timeLeft.minutes = Math.floor(ms / 60000);
        info.timeLeft.seconds = Math.floor(ms % 60000 / 1000);
        info.timeLeft.onlySeconds = info.timeLeft.minutes * 60 + info.timeLeft.seconds;
        info.timeLeft.minutes = info.timeLeft.minutes.toString().replace(/^([0-9])$/, '0$1');
        info.timeLeft.seconds = info.timeLeft.seconds.toString().replace(/^([0-9])$/, '0$1');
        if (!info.warned && info.timeLeft.onlySeconds <= opts.warningTime) {
            info.warned = true;
            opts.onWarning(els, info, opts);
        } else if (!info.expired && info.timeLeft.onlySeconds < 0) {
            info.expired = true;
            opts.onExpire(els, info, opts);
        }
        if (!info.expired) {
            opts.onTick(els, info, opts);
        }
    };

    function onTick(els, info, opts) {
        els.each(function() {
            opts.onTickEach(this, info, opts);
        });
    };

    function onTickEach(el, info, opts) {
        var pval = ((info.timeLeft.minutes * 60) + parseInt(info.timeLeft.seconds)) * 100 / opts.warningTime;

        $(el).html(info.timeLeft.minutes + ':' + info.timeLeft.seconds); //+ ' ' + opts.warningTime + ' ' + pval + '  ' + info.duration);
        if (pval < 100) {
            if (!$("#Session-TimeOut").dialog('isOpen'))
                $("#Session-TimeOut").dialog('open');
            $(".bar").progressbar({
                value: pval
            });
        }
        else {
            if ($("#Session-TimeOut").dialog('isOpen'))
                $("#Session-TimeOut").dialog('close');
        }
    };

    function onWarning(el, info, opts) {
        //alert('Warning');
        $("#Session-TimeOut").dialog('open');

    };

    function onExpire(el, info, opts) {
        window.location('Login.aspx');
        //alert('Expired');
    };

    // public
    $.fn.sessionTimeout.readCookie = function(name) {
        var nameEQ = name + "=";
        var ca = document.cookie.split(';');
        for (var i = 0; i < ca.length; i++) {
            var c = ca[i];
            while (c.charAt(0) == ' ') c = c.substring(1, c.length);
            if (c.indexOf(nameEQ) == 0)
                return unescape(c.substring(nameEQ.length, c.length));
        }
        return null;
    }

    $.fn.sessionTimeout.defaults = {
        timeCookie: 'SERVERTIME',//cookie 
        sessCookie: 'SESSIONTIMEOUT', //cookie
        interval: 1000,
        onTick: onTick,
        onTickEach: onTickEach,
        warningTime: 340, // seconds
        onWarning: onWarning,
        onExpire: onExpire
    };
})(jQuery);


The plugin provides .sessionTimeout(options) which is used on your selected elements to display the amount of time left until session expiration. The options allow you to use different cookie names, change the execution interval and override several events.
It works by setting up a periodic function to watch the cookies. Whenever the cookies are updated, we recalculate the time out and continue displaying the information. If the warning time or expiration is reached, it fires off over-ridable events that by default use “alert” to display simple messages, but could easily use something like the jQuery UI dialog plugin.
If you’re wondering about the reasoning behind the server time cookie. This was to workaround the differences between the client and server clocks.

Example


In the following code I’ll set the two cookies required for the plugin and use it against two different elements. One for displaying the time, another to show a progress bar (using jQuery UI, not required for the plugin). I also override the onWarning & onExpire events for the progress bar since the user wouldn’t like to be double prompted

Add Jquery And Jquery UI

  <link href="../App_Themes/TestTheme/jquery-ui-1.8.2.custom.css" rel="stylesheet"
        type="text/css" />
    <link href="../App_Themes/TestTheme/stylemain.css" rel="stylesheet" type="text/css" />
    <script src="../JS/jquery-1.4.2.min.js" type="text/javascript"></script>
    <script src="../JS/jquery-ui-1.8.2.custom.min.js" type="text/javascript"></script>
    <script src="../JS/Timeout.js" type="text/javascript"></script>    


Init Session Timeout And a Dialog Box To Dispaly Alert
          $(document).ready(function() {
            $(".sessions").sessionTimeout();
            $("#Session-TimeOut").dialog({
                resizable: true,
                height: 200,
                autoOpen: false,
                modal: true,
                buttons: {
                    Ok: function() {
                        $(this).dialog('close');
                        __doPostBack('<%= Button1.UniqueID %>', '');
                    }
                }
            });
        });   


default.aspx
   
Your session is about to Expire.




add cookie on PageLoad

  HttpCookie appCookie = new HttpCookie("SERVERTIME");
        appCookie.Value = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");
        appCookie.Expires = DateTime.Now.AddDays(1);
        appCookie.Path = "/";
        Response.Cookies.Add(appCookie);
        HttpCookie appCookie2 = new HttpCookie("SESSIONTIMEOUT");
        appCookie2.Value = DateTime.Now.AddMinutes(HttpContext.Current.Session.Timeout).ToString("yyyy/MM/dd HH:mm:ss");
        appCookie2.Expires = DateTime.Now.AddDays(1);
        appCookie2.Path = "/";
        Response.Cookies.Add(appCookie2);

Running this bit of JavaScript fires the alert shown below:

Download

22 comments:

  1. Amazing but Will this run with if put in master page. This is exactly what I need can you please post a sample project with master page.

    Regards
    Roy

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
  3. Could you please send me a sample project? if yes plz reply me I will share my emailId.

    ReplyDelete
  4. few things i am thinking after seeing a similar plug in that has some other good features. working on merging the two together.

    1) i put the cookie in my global pre_request event this way only need to modify one place.
    2) instead of adding the div to the page why not append to the body of page in the plug in so that just a call to the sessionTimeout and will set up div and all.

    ReplyDelete
    Replies
    1. Thank u for your response and information

      Chris.

      Delete
  5. I am using your script in my project. Can you send me styles and javascript files?

    ReplyDelete
  6. Where is the session timeout set??????

    ReplyDelete
    Replies
    1. in web.config
      <sessionState mode="InProc" timeout="20">

      Delete
  7. thank you somesh.. I tried this even before reading this article but i was unable to read session set in asp.net with value and expiry from jquery. when i try to read i'm geting [object Object] but not the value...if i dont set any expiry to the cookie then i'm getting the cookie value in jquery.

    ReplyDelete
  8. finally working...thank you so much for work and time

    ReplyDelete
  9. Sir,
    Can u please help me as in where to put which part of code. i am totally confused. i want that the user should be logged out and redirected to the login page after a certain period of inactivity.

    ReplyDelete
    Replies
    1. Hi,
      Please download sample project

      https://www.box.com/s/cyrxoqu2mtxkvima0796

      sorry for the late response.. :)

      Delete
  10. Hello Sir,
    Will this work for the website without master pages?
    I have tried a few other examples but they never work out if there are more than one pages in your website.
    I need to implement this asap please help

    ReplyDelete
    Replies
    1. yes.. This will work with out master page..

      Delete
    2. So I will have to add this code to each and every page of my website?????
      In that case it will definately work I think.

      Delete
    3. Sir, Can you send me a sample project in order to implement this without master pages?????

      Delete
    4. Yes if u want to do without master page,you have to add this in every page..


      download sample project

      Delete
    5. or you could force it into every page using server injection or adding it with the global events

      Delete
  11. Hi,
    Can you pls send sample code for session timeout. I'm unable to download.
    Thanks in advance

    ReplyDelete