Display Session timeout warning message before Session expires in ASP.NET Core

17,981

You already have session timeout code in your question. By the way, default value is 20 minutes. If you want more information, you can read more at Configuring Session.

As far as, I know ASP.NET doesn't have a build-in mechanism to display session expire notification message. So, we have to write our own.

Here is mine, and here is the usage. You are feel free to use it. Since I use Kendo UI, I use Kendo UI Window for the dialog. You could replace it with jQuery UI, if you do not want to use Kendo UI.

enter image description here

_SessionExpireNotification.cshtml

I keep the setting inside appsettings.json. You could hard coded them in this file.

@using Asp.Core
@using Microsoft.Extensions.Options
@using Asp.Web.Common

@inject IUserSession UserSession
@inject IOptions<AppSettings> AppSettings

@if (UserSession.IsAuthenticated)
{
    @(Html.Kendo().Window()
          .Name("SessionExpireNotification")
          .Title("Need More Time?")
          .Modal(true)
          .Content(@<text>
            <p>
                Your session is about to expire. You will be automatically signed out in
            </p>
            <h2 style="margin-top: 0">
                <span id="logout-counter-span">0@(AppSettings.Value.CookieAuthentication.SessionExpireNotificationMinutes):00</span>
            </h2>
            <p>
                To continue your session, select <strong>Stay Signed In</strong>.
            </p>
            <p>
                <button id="stay-logged-in-button" type="button" class="btn btn-primary">
                    Stay Signed In
                </button>
                <button id="signout-button" type="button" class="btn btn-default">
                    Sign out
                </button>
            </p>
        </text>)
          .Width(450)
          .Visible(false)
          .Events(ev => ev.Close("onSessionExpireNotificationClose"))
    )

    <script>

        var notificationInterval,
            logoutInterval,
            logoutCounterSpan;

        function startNotificationCounter() {
            var counter = @AppSettings.Value.CookieAuthentication.ExpireMinutes;
            notificationInterval = setInterval(function() {
                    counter--;
                    if (counter === @AppSettings.Value.CookieAuthentication.SessionExpireNotificationMinutes) {
                        $("#SessionExpireNotification").data("kendoWindow").center().open();
                        startLogoutCounter();
                    }
                },
                60000);
        }

        function startLogoutCounter() {
            var counter = @(AppSettings.Value.CookieAuthentication.SessionExpireNotificationMinutes*60);
            logoutInterval = setInterval(function() {
                    counter--;
                    if (counter < 0) {
                        $("#logoutForm").submit();
                    } else {
                        var m = Math.floor(counter / 60);
                        var s = Math.floor(counter % 60);
                        var mDisplay = m < 10 ? "0" + m : m;
                        var sDisplay = s < 10 ? "0" + s : s;
                        logoutCounterSpan.text(mDisplay + ":" + sDisplay);
                    }
                },
                1000);
        }

        function resetCounters() {
            clearInterval(notificationInterval);
            clearInterval(logoutInterval);
            logoutCounterSpan.text("0@(AppSettings.Value.CookieAuthentication.SessionExpireNotificationMinutes):00");
            startNotificationCounter();
        }

        function onSessionExpireNotificationClose() {
            resetCounters();
        }

        $(function() {
            logoutCounterSpan = $("#logout-counter-span");

            startNotificationCounter();

            $("#stay-logged-in-button").click(function() {
                $.get("@Url.Action("Index", "KeepAlive", new {area = ""})",
                    null,
                    function(data) {
                        resetCounters();
                        $("#SessionExpireNotification").data("kendoWindow").center().close();
                    }
                );
            });

            $("#signout-button").click(function() {
                $("#logoutForm").submit();
            });
        });

    </script>
}

Extending the session timeout is easy. You just call a dummy action method.

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace Asp.Web.Controllers
{
    [AllowAnonymous]
    public class KeepAliveController : Controller
    {
        //
        // GET: /KeepAlive
        [AllowAnonymous]
        public ActionResult Index()
        {
            return Content("I am alive!");
        }
    }
}
Share:
17,981
Amulu
Author by

Amulu

Updated on June 05, 2022

Comments

  • Amulu
    Amulu almost 2 years

    I can able to set the session end the below code.

    services.AddSession(options => { options.IdleTimeout = TimeSpan.FromMinutes(2); });

    I need to extend the session after 20 minutes and if show the session time out warning message to the user and so the user can extend their time out from the application UI.

    • Bojan Petkovic
      Bojan Petkovic over 6 years
      what do you have so far? Did you try something, did it fail?
  • Amulu
    Amulu over 6 years
    Thank you so much Win. Could you please provide me the code with Jquery?
  • Lonely Planeteer
    Lonely Planeteer about 6 years
    It's actually a great solution. Can I do it in MVC 5?
  • Win
    Win about 6 years
    @LonelyPlaneteer Definitely. Howerver, ASP.NET MVC 5 doesn't have appsettings.json, so you will have to either hard code those setting inside JavaScript or place them inside web.config. The rest should be same between ASP.NET MVC 5 and ASP.NET Core.
  • Lonely Planeteer
    Lonely Planeteer about 6 years
    Thanks. I have already implemented the solution MVC 5. Working like a charm. But I am stuck with another problem. In my application I have three different layout. _Layout, _EmployeeLayout, _CustomerLayout I have added @Html.Partial("_SessionExpireNotification") to each layout. Now all pages have different counter. How can I make one counter for all layouts? For example, when I go to employee page, it should reset values for other two. I am not sure whether problem is clear or not. Please suggest. Thanks in advance.
  • Win
    Win about 6 years
    @LonelyPlaneteer If you open each pages in different tabs or different browsers, there is nothing you can do about it.
  • infocyde
    infocyde about 6 years
    Thanks for your code. One issue though, the Keep alive, for some reason on multiple sites I've built just pinging the site like above DOES NOT keep the session alive, anyone have any idea why?
  • Win
    Win about 6 years
    @infocyde Could you create a new question with mcv? I'm happy to take a look at it.
  • Nick
    Nick almost 4 years
    I had to adapt this to fit my needs, but was an excellent base for handling this situation in .NET Core. I did have to specifically multiply one of the counters by 60 because it was assuming that the minutes were in seconds already, I believe. The counter wasn't working right until I did add that tweak. Thank you!
  • Tundey
    Tundey almost 4 years
    Does calling the logout form after the session has expire matter? After all, the session should already be dead on the server 'cos of inactivity. @Win