Search code examples
c#asp.net-mvc-4session-variablesactionfilterattribute

Session expiration attribute doesn't get fired at the server


I'm trying to track session expiration and everything works fine when the application is running on my development PC. but It doesn't work on the live server as expected. I already restart the server but no luck! I'm running on windows server 2012 (windows azure vm) and IIS 8.

I'm receiving a similar error based on controller whose action is fired. Error is generated because the controller is failed to initialize as the session variable _connectionstring is null when the session is expired.

If I changed the sessionState to 1 and form timeout to 2 and then the redirection worked perfectly in the both server and development environments. Strange!!

My question is why the action filter is miss behaving on the live server environment? It works perfectly fine under development environment. what do I missing here?

Following is my code.

Web.Config:

<system.web>
    <sessionState mode="InProc" timeout="20" />
    <authentication mode="Forms">
        <forms loginUrl="~/Auth/Login" timeout="25" slidingExpiration="true" />
    </authentication>
</system.web>

Filter Config:

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
        filters.Add(new SessionExpireFilterAttribute());
        filters.Add(new LocsAuthorizeAttribute());
    }
}

Filters:

public class SessionExpireFilterAttribute : ActionFilterAttribute
{

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext.ActionDescriptor.GetCustomAttributes(typeof(SkipActionFilterAttribute), false).Any())
        {
            return;
        }

        HttpContextBase ctx = filterContext.HttpContext;
        //HttpContext ctx = HttpContext.Current;

        // check if session is supported
        if (ctx.Session != null)
        {
            // check if a new session id was generated
            if (ctx.Session.IsNewSession)
            {
                // If it says it is a new session, but an existing cookie exists, then it must
                // have timed out
                string sessionCookie = ctx.Request.Headers["Cookie"];
                if ((null != sessionCookie) && (sessionCookie.IndexOf("ASP.NET_SessionId") >= 0))
                {
                    if (filterContext.HttpContext.Request.IsAjaxRequest())
                    {
                        // For AJAX requests, we're overriding the returned JSON result with a simple string,
                        // indicating to the calling JavaScript code that a redirect should be performed.
                        filterContext.Result = new JsonResult { Data = "_Logon_" };
                    }
                    else
                    {
                        filterContext.Result = new RedirectToRouteResult(
                            new RouteValueDictionary {
                            { "action", "SessionTimeout" },
                            { "controller", "Session" }});
                    }
                }
            }
        }

        base.OnActionExecuting(filterContext);
    }
}

//[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class LocsAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (filterContext.ActionDescriptor.GetCustomAttributes(typeof(SkipActionFilterAttribute), false).Any())
        {
            return;
        }
        HttpContext ctx = HttpContext.Current;

        // If the browser session has expired...
        if (ctx.Session["UserName"] == null)
        {
            if (filterContext.HttpContext.Request.IsAjaxRequest())
            {
                // For AJAX requests, we're overriding the returned JSON result with a simple string,
                // indicating to the calling JavaScript code that a redirect should be performed.
                filterContext.Result = new JsonResult { Data = "_Logon_" };
            }
            else
            {
                // For round-trip posts, we're forcing a redirect to Home/TimeoutRedirect/, which
                // simply displays a temporary 5 second notification that they have timed out, and
                // will, in turn, redirect to the logon page.
                filterContext.Result = new RedirectToRouteResult(
                    new RouteValueDictionary {
                            { "action", "SessionTimeout" },
                            { "controller", "Session" }});
            }
        }
        else if (filterContext.HttpContext.Request.IsAuthenticated)
        {
            // Otherwise the reason we got here was because the user didn't have access rights to the
            // operation, and a 403 should be returned.
            filterContext.Result = new HttpStatusCodeResult(403);
        }
        else
        {
            base.HandleUnauthorizedRequest(filterContext);
        }
    }
}

public class SkipActionFilterAttribute : Attribute
{
}

Solution

  • Finally I found the reason for the misbehavior.

    My action filter doesn't fire as IIS > Application Pools > Advance Settings> idle timeout (minutes) setting reaches the timeout before my session state. Default value is 20.

    Setting the value to 0 will disable the IIS idel timeout.