cdub
cdub

Reputation: 25731

Session Timeout Warning in ASP.NET

I have an asp.net site that I need to have a popup/layer/alert happen when the session reaches its timeout (lets say 10 minutes). The popup will say that your account session will exprire due to inactivity and have a button for continue session or a button for logout.

I see different ways to do this online, but what's the best/proper way to handle this? Do I have to put an additional timeout if the popup is open too long?

Upvotes: 17

Views: 67288

Answers (7)

Pranay Rana
Pranay Rana

Reputation: 176936

<script type="text/javascript">
    var sessionTimeoutWarning = "<%= System.Configuration.ConfigurationManager.AppSettings["SessionWarning"].ToString()%>";
        var sessionTimeout = "<%= Session.Timeout %>";

    var sTimeout = parseInt(sessionTimeoutWarning) * 60 * 1000;
    setTimeout('SessionWarning()', sTimeout);

    function SessionWarning() {
        var message = "Your session will expire in another " +
            (parseInt(sessionTimeout) - parseInt(sessionTimeoutWarning)) +
            " mins! Please Save the data before the session expires";
        alert(message);
    }
</script>

Upvotes: 27

UTHIRASAMY
UTHIRASAMY

Reputation: 1

What you can do is use some javascript to fire the message. Use a timer to fire after a certain period (period set for session time out in your application - a couple of minutes).

After that period, show a confirmation dialog to the user that session will time out. If the user clicks to keep the sesion. Make a dummy postback in the page so that the session is not lost. You can also make an AJAX call so that user does not see the page reloading and loses input data.

Upvotes: 0

Damian Vogel
Damian Vogel

Reputation: 1192

I went to see the article from the post of Pranay Rana, and I like the general idea, but the code could use some streamlining. So here is my version. For tablet / mobile issues see below:

<script language="javascript" type="text/javascript">
    var minutesForWarning = 4;
    var sessionTimeout = parseInt("@Session.Timeout"); // razor syntax, otherwise use <%= Session.Timeout %>
    var showWarning = true;

    function SessionWarning() {
        showWarning = false;
        alert("Your session will expire in " + minutesForWarning + " mins! Please refresh page to continue working.");
        // leave a second for redirection fct to be called if expired in the meantime
        setTimeout(function () { showWarning = true; }, 1000);
    }

    function RedirectToWelcomePage() {
        if (showWarning)
            alert("Session expired. You will be redirected to welcome page.");
        document.getElementById('logoutForm').submit();
        // window.location = "../Welcome.aspx"; // alternatively use window.location to change page
    }

    setTimeout('SessionWarning()', (sessionTimeout - minutesForWarning) * 60 * 1000);
    setTimeout('RedirectToWelcomePage()', sessionTimeout * 60 * 1000);
</script>

Well, on tablets or mobiles, you can't count on the setTimeout, as javascript execution is suspended when the device is locked or browser inactive. Instead, I'm doing a periodical check (in my case, I esteem every 10s to be enough):

<script language="javascript" type="text/javascript">
    function addMinutes(date, minutes) {
        return new Date(date.getTime() + minutes * 60 * 1000);
    }
    function remainingMinutes(date) {
        return Math.round((date - (new Date()).getTime()) / 60 / 1000);
    }

    var minutesForWarning = 5;
    var sessionTimeout = parseInt("@Session.Timeout");
    var showWarning = true;
    var showRedirect = true;
    var timeToWarn = addMinutes(new Date(), sessionTimeout - minutesForWarning);
    var timeToEnd = addMinutes(new Date(), sessionTimeout);

    function CheckTime() {
        if (showWarning && new Date() > timeToWarn && new Date() < timeToEnd) {
            showRedirect = false;
            showWarning = false;
            alert("Your session will expire in " + remainingMinutes(timeToEnd)) + " mins! Please refresh page to continue working.");
        }
        if (new Date() > timeToEnd) {
            if (showRedirect)
                alert("Session expired. You will be redirected to welcome page ");
            document.getElementById('logoutForm').submit();
            // window.location = "../Welcome.aspx"; // alternatively use window.location to change page
        }
        if (showRedirect == false)
            showRedirect = true;
    }

    setInterval(CheckTime, 10000);

</script>

Upvotes: 4

moomoo
moomoo

Reputation: 906

Below is some JavaScript with jQuery to warn the user about ASP.NET Forms Authentication timeout and will redirect them to the login page if timeout is reached. It could be improved and adapted for session timeout as well. It will also reset the authentication timeout by "pinging" the server whenever the user interacts with the page by clicking, typing or resizing.

Note that this does add load to the server by pinging with every click, key press, resize but it's pretty minimal. Still, if you have many users typing away you will need to evaluate the impact. I couldn't think of another way to do this because the server has to be involved since that's where the timeout is expiring.

Also note that the timeout is not hard-coded in the JS. It get's the timeout from the server so you only need to maintain it in one place in Web.config.

(function ($, undefined) {

    if (!window.session) {

        window.session = {

            monitorAuthenticationTimeout: function (redirectUrl, pingUrl, warningDuration, cushion) {

                // If params not specified, use defaults.
                redirectUrl = redirectUrl || "~/Account/Login";
                pingUrl = pingUrl || "~/Account/Ping";
                warningDuration = warningDuration || 45000;
                cushion = cushion || 4000;

                var timeoutStartTime,
                    timeout,
                    timer,
                    popup,
                    countdown,
                    pinging;

                var updateCountDown = function () {
                    var secondsRemaining = Math.floor((timeout - ((new Date()).getTime() - timeoutStartTime)) / 1000),
                        min = Math.floor(secondsRemaining / 60),
                        sec = secondsRemaining % 60;

                    countdown.text((min > 0 ? min + ":" : "") + (sec < 10 ? "0" + sec : sec));

                    // If timeout hasn't expired, continue countdown.
                    if (secondsRemaining > 0) {
                        timer = window.setTimeout(updateCountDown, 1000);

                    }
                    // Else redirect to login.
                    else {
                        window.location = redirectUrl;
                    }
                };

                var showWarning = function () {
                    if (!popup) {
                        popup = $(
                            "<div style=\"text-align:center; padding:2em; color: black; font-color: black; background-color:white; border:2px solid red; position:absolute; left: 50%; top:50%; width:300px; height:120px; margin-left:-150px; margin-top:-90px\">" +
                                "<span style=\"font-size:1.4em; font-weight:bold;\">INACTIVITY ALERT!</span><br/><br/>" +
                                "You will be automatically logged off.<br/><br/>" +
                                "<span style=\"font-size:1.4em; font-weight:bold;\" id=\"countDown\"></span><br/><br/>" +
                                "Click anywhere on the page to continue working." +
                            "</div>")
                            .appendTo($("body"));

                        countdown = popup.find("#countDown");
                    }

                    popup.show();
                    updateCountDown();
                };

                var resetTimeout = function () {
                    // Reset timeout by "pinging" server.
                    if (!pinging) {
                        pinging = true;
                        var pingTime = (new Date()).getTime();
                        $.ajax({
                            type: "GET",
                            dataType: "json",
                            url: pingUrl,
                        }).success(function (result) {

                            // Stop countdown.
                            window.clearTimeout(timer);
                            if (popup) {
                                popup.hide();
                            }

                            // Subract time it took to do the ping from
                            // the returned timeout and a little bit of 
                            // cushion so that client will be logged out 
                            // just before timeout has expired.
                            timeoutStartTime = (new Date()).getTime();
                            timeout = result.timeout - (timeoutStartTime - pingTime) - cushion;

                            // Start warning timer.
                            timer = window.setTimeout(showWarning, timeout - warningDuration);
                            pinging = false;
                        });
                    }
                };

                // If user interacts with browser, reset timeout.
                $(document).on("mousedown mouseup keydown keyup", "", resetTimeout);
                $(window).resize(resetTimeout);

                // Start fresh by reseting timeout.
                resetTimeout();
            },
        };
    }

})(jQuery);

Simply call the above once when your page loads:

window.session.monitorAuthenticationTimeout(
        "/Account/Login",    // You could also use "@FormsAuthentication.LoginUrl" in Razor.
        "/Account/Ping");

On the server, you'll need an action that returns the remaining time. You could add more information as well.

    public JsonResult Ping()
    {
        return Json(new { 
                        timeout = FormsAuthentication.Timeout.TotalMilliseconds 
                    }, 
                    JsonRequestBehavior.AllowGet);
    }

Upvotes: 1

Samuel Goldenbaum
Samuel Goldenbaum

Reputation: 18929

You could you jquery and the setinterval function to do an Ajax post behind the scenes to refresh the timeout, if using sliding expiration, or get the value of time remaing by recording the session start time and subtracting from the expiration time.

Upvotes: 0

Joseph Caruana
Joseph Caruana

Reputation: 2271

You will have to use client side technology for here (javascript). Using for example you would use javascript timeout facility and then show the warning. If user clicks ok you can need to do something to keep the session alive. I would sugest using jquery.ajax method, and making a call to the server, can be a dummy call - just to keep the session alive.

Upvotes: 0

StuartLC
StuartLC

Reputation: 107317

This has been addressed before, e.g. ASP.NET - Javascript timeOut Warning based on sessionState timeOut in web.config

However, AFAIK there isn't a totally reliable way to do this, since:

  • If the user has more than one window open using the same session, then one window may be more recent than the other and the client session timeouts on the oldest window would be stale / incorrect.
  • If you round trip to the server to see what the current session expiration is, you will extend it, thus defeating the purpose of the popup / alert.

Upvotes: 7

Related Questions