Display session expire popup in ASP.Net MVC

In this tutorial, we are going to implement session expiry popup in an ASP.Net MVC application. It is most common requirement to alert user by showing a warning popup ahead of time before the actual session expires. We use Timeout-dialog.js JQuery plugin by Rodrigo Neri (We specifically take Michael Khalili’s timeout-dialog’s fork) to show the session expiry popup. Popup will be having an option to stay signed-in otherwise user will be logged out on Session expiration.

NOTE: The following tutorial is targeted only for application running in a single browser tab. In case if application is running in multiple browser tabs, then timeout dialogs will be loaded separately on each browser tab (not at once, but based on the time when the tab is loaded). Redirection to logout endpoint in one browser tab will not result in redirection of other tabs. If we need to support multiple browser tabs, we have to use HTML5 Web Storage to communicate between different browser tabs.

Lets get started by creating an ASP.Net MVC4 Application. For testing purpose, I made the web.config’s sessionState timeout property (under system.web node) to have 2 minutes.

<sessionState timeout="2"></sessionState>

Download the following Timeout-dialog files.

  1. timeout-dialog.js (place it in Scripts folder of VS solution)
  2. timeout-dialog.css (place it in Content folder of VS solution)
  3. timeout-icon.png (place it in Images folder of VS solution)

Make the following change in timeout-dialog.css to support timeout-icon.png from images folder of VS solution.

.timeout-dialog {
  padding: 15px;
  position: absolute;
  background: #eeeeee url("../images/timeout-icon.png") no-repeat 15px 25px;
  border: 1px solid #ffffff;
  -webkit-box-shadow: 0 0px 5px rgba(0, 0, 0, 0.5);
  -moz-box-shadow: 0 0px 5px rgba(0, 0, 0, 0.5);
  box-shadow: 0 0px 5px rgba(0, 0, 0, 0.5);
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
  border-radius: 5px;
}

We have to make the following change in timeout-dialog.js file. Instead of this.settings.restart_on_yes, it has to be self.settings.restart_on_yes.

image

        keepAlive: function () {
            var self = this;
            this.destroyDialog();
            window.clearInterval(this.countdown);

            this.settings.keep_alive_function();

            if (this.settings.keep_alive_url !== '') {
                $.get(this.settings.keep_alive_url, function (data) {
                    if (data === "OK") {
                        if (self.settings.restart_on_yes) {
                            self.setupDialogTimer();
                        }
                    }
                    else {
                        self.signOut(false);
                    }
                });
            }
        },

Include above files in _layout.cshtml as shown below. JQuery and JQuery UI is required as pre-requisites for timeout dialog.

    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/jqueryui")
    <link href="~/Content/timeout-dialog.css" rel="stylesheet" />
    <script src="~/Scripts/timeout-dialog.js"></script>

    @RenderSection("scripts", required: false)
    <script>
        $(function () {
            var fnTimeOut = function () {
                jQuery.timeoutDialog.setupDialogTimer({
                    timeout: 105,
                    countdown: 100,
                    logout_redirect_url: '@Url.Action("Logout", "Home")',
                    keep_alive_url: '@Url.Action("Keepalive", "Home")'
               });
            };
            fnTimeOut();
        });
    </script>

In above code, we have following properties configured (There are other properties as well which can be configured for timeout-dialog, please refer to timeout-dialog’s documentation).

timeout: This values represents the session timeout value in seconds. Popup will be opened at (timeout – countdown) seconds.

countdown: The value (in seconds) which will be ticked on popup.

logout_redirect_url: When logout happens, application redirects to this endpoint.

restart_on_yes: Indicates if the countdown should restart when the user clicks the keep session alive button.

keep_alive_url: A GET request will be made to keep the session alive. This GET expects a ‘OK’ plain HTTP response.

Create below endpoints. SetSession is the endpoint which will set the session, Keepalive endpoint is used to extend the session value from timeout dialog popup. Logout endpoint is used to abandon the session. which will be used to logout the user.

    public class HomeController : Controller
    {
        public ActionResult SetSession()
        {
            Session["Test"] = "Test Value";
            return View();
        }

        public ActionResult Keepalive()
        {
            return Json("OK", JsonRequestBehavior.AllowGet);
        }

        public ActionResult Logout()
        {
            Session.Abandon();
            return View();
        }
    }

SetSession view is very simple which just displays the session value as shown below.

@{
    ViewBag.Title = "SetSession";
}

<h2>SetSession</h2>
<div>@(Session["Test"] == null ? "empty" : Session["Test"].ToString())</div>

Logout view is as shown below.

@{
    ViewBag.Title = "Logout";
}

<h2>Logout</h2>

Now lets run the application and navigate to /Home/SetSession endpoint.

image

After a minute (as we configured session timeout for 2 minutes) we should get the timeout dialog. In the following minute if we do not perform any action then user will be redirected to Logout endpoint. If user performs Yes, Keep me signed in action, then a call will be made to Keepalive action and session will be extended for further 2 minutes. And after the subsequent 2 minutes, timeout dialog will be displayed again.

image

Either when we click on No, Sign me out option or wait till the timer elapsed, we will be redirected to Logout endpoint.

image

Above approach will work for full page refresh or postback, now lets see how we are going to handle AJAX calls. We need to take care of AJAX calls because when an AJAX call is made session will be extended on server, so we need to reset the timer on client side. Let’s include following AJAX call in SetSession view.

@{
    ViewBag.Title = "SetSession";
}

<h2>SetSession</h2>
<div>@(Session["Test"] == null ? "empty" : Session["Test"].ToString())</div>

<input type="button" value="Click Here" id="btn1" />

@section scripts{
    <script>
        $(function () {
            $("#btn1").click(function () {
                $.get("@Url.Action("AjaxClick", "Home")", function (data) {
                    jQuery.timeoutDialog.setupDialogTimer();
                });
            });
        });
    </script>
}

Add the following action to the controller.

    public ActionResult AjaxClick()
    {
        return Json("OK", JsonRequestBehavior.AllowGet);
    }

Run the application and keep hitting AJAX Click Here button. After the last AJAX call, timer will start and we will get session timeout popup exactly in the same way as shown above.

If we don’t want to dilute the every success callback code of AJAX call, we can handle ajaxComplete event at global level and place session timeout code as shown below.

<script>
    $(function () {
        $("#btn1").click(function () {
            $.get("@Url.Action("AjaxClick", "Home")", function (data) {
                console.log(data);
            });
        });
    });

    $(document).ajaxComplete(function () {
        jQuery.timeoutDialog.setupDialogTimer();
    });
</script>

That’s it for now, Happy Coding and Stay Tuned!!!

You may also like...