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?
The Session object is used to persist data across a user session during the user's visit to a website. In asp.net by default session timeout = 20 minutes, but in some cases we need to change session time increment or decrement by changing web. config file setting.
There are two ways to set a session timeout in ASP.NET. First method: Go to web. config file and add following script where sessionstate timeout is set to 60 seconds.
The Timeout property cannot be set to a value greater than 525,600 minutes (1 year). The default value is 20 minutes.
<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>
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:
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>
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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With