I'm having this issue with my current session manager, when the session expires it will not log off the user.
At random intervals while user is logged in the HttpContext.Current
is NULL
causing the site to generate many errors. I've tried a couple of techniques to redirect user to login upon session expiration, with no success.
- Under
Global.asax
I'm making use ofSession_End
can attempted to callLogOut
method but this gets executed even before user logs in. - Under
Global.asax
I addedApplication_AcquireRequestState
, but sadly this makes way to many calls to the SSO Service. Also, it never redirected to login upon session expiration. I tested it with the followingFormsAuthentication.RedirectToLoginPage()
; No luck.
I found this answer by Lex Li "Why HttpContext.Current be null?" - it gave me some insight on what my problem could be, even-though my application doesn't make use of background-threads, my HttpContext.Current
comes back Null with some random requests, doesn't always happen.
Session Manager
public class SessionManager
{
private const string SessionKey = "AppSession";
private SessionManager()
{
GUID = new Guid();
FirstName = String.Empty;
LastName = String.Empty;
Email = String.Empty;
SessionExpiration = new DateTime();
}
// Gets the current session.
public static SessionManager Current
{
get
{
if(HttpContext.Current != null)
{
if (HttpContext.Current.Session[SessionKey] == null)
{
var model = new SessionManager();
HttpContext.Current.Session[SessionKey] = model;
}
return (SessionManager)HttpContext.Current.Session[SessionKey];
}
else
{
return null;
}
}
}
public static void LogOffUser()
{
//SSO is a seperate service, I need to stay insync.
var ssoAuth = new SSOAuth();
if(Current != null)
ssoAuth.SSOLogoffUser(Current.GUID);
FormsAuthentication.SignOut();
FormsAuthentication.RedirectToLoginPage();
}
public Guid GUID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public DateTime SessionExpiration { get; set; }
}
Login Controller
[HttpPost]
[AllowAnonymous]
public JsonResult Login(LoginViewModel user)
{
var ssoAuth = new SSOAuth();
var sessionObject = ssoAuth.SSOLoginUser(user.Email, user.Password);
if (sessionObject != null && sessionObject.SessionId != Guid.Empty)
{
SessionManager.Current.Email = sessionObject.UserId;
SessionManager.Current.GUID = sessionObject.SessionId;
SessionManager.Current.FirstName = sessionObject.FirstName;
SessionManager.Current.LastName = sessionObject.LastName;
SessionManager.Current.SessionExpiration = sessionObject.SessionExpiration;
//Grab difference in time to get session timeout in minutes.
var differenceInTime = SessionManager.Current.SessionExpiration - DateTime.Now;
Session.Timeout = differenceInTime.Minutes;
//Authenticate user
FormsAuthentication.SetAuthCookie(user.Email, false);
//We return JSON, Its an AJAX Call.
return Json(new
{
redirectUrl = "/Home.mvc/Home/Index",
isRedirect = true
});
}
return Json(new
{
redirectUrl = string.Empty,
isRedirect = false
});
}
I think that you may need to verify that you have this set in your web.config
It seems that you may not have the task friendly awaits and that will cause unexpected behaviors such as this. You may refer to the similar problem posed here and the solution.
Now, you may not be using Asynchronous code in your soution, but that doesn't mean that it isn't being used by the framework. Regardless, I think it is worth a shot.
As confirmed in the comments, you're setting your application pool's
Maximum number of worker processes
to a value higher than 1 and useIn-Process Mode
for session state.I'm pretty sure this is the problem of
HttpContext.Current.Session
being null randomly instead ofHttpContext.Current
.InProc
session state andmultiple working processes
are not compatible. WithInProc
session state, your session state is stored in worker processes memory and is not shared between worker processes => that results in session state being lost randomly when your requests are served by different processes.In your case, setting
Maximum number of worker processes
to 1 should fix the issue.If you're looking for a multiple working processes solution, you should store your session state out of process using either a session state service or a database: http://tutorials.csharp-online.net/ASP.NET_State_Management%E2%80%94Storing_Session_State_out_of_Process
This sounds suspiciously like it may be a session vs. forms authentication timing issue similar to Forms Authentication Timeout vs Session Timeout
Make sure your Forms timeout is at least 2x your session timeout.