Accessing Session in background service using HttpModule - asp.net

I am trying to create a background service in asp.net which checks for session timeouts and redirects the user to a timeout page ( not the login page ). My code is like this
public class SessionTimeoutModule : IHttpModule
{
private static Timer timer;
//Test value
private const int interval = 1000 * 1 * 10;
public void Init( HttpApplication application )
{
if ( timer == null )
{
timer = new Timer( new TimerCallback( CheckSessionTimeout ),
application.Context, 0, interval );
}
}
private void CheckSessionTimeout( object sender )
{
HttpContext ctx = (HttpContext)sender;
if ( ctx.Session != null && ctx.Session.IsNewSession )
{
var cookie = ctx.Request.Headers["Cookie"];
if ( cookie != null )
{
if ( cookie.ToUpper().IndexOf( "ASP.NET_SESSIONID" ) >= 0 )
{
ctx.Response.Redirect( "" );
}
}
}
}
public void Dispose()
{
timer = null;
}
}
The problem here is that i am not able to get the session value in the CheckSessionTimeout method. It is always null. How can get the Session here.
I have looked at this solution but it doesnt help.

I'm afraid you are on the wrong track here. You cannot implement a background service using an HttpModule like this. The HttpContext you are passing around is bound to an HTTP request, and I'm quite sure you should not keep it around like you're trying to do. Also even if you could detect the session time-out, there would be no way to redirect the user to a new page without an active request.
You might find this thread helpful.

I think there is a logical mistake here, even if you fix your code, you will never get an ended session.
if you can access to a session, it will have a sessionID. You can not get a session which ended by timeout by this way.
Maybe you should use global.asax's session_end. but I'm not sure it will help.
Also in here you can see, SessionID is not replaced until Session.Abandon.

Related

How to Redirect or Close Browser after Session TimeOut in ASP.NET?

I have a Catcha value( Security Code ) that is store in Session on PageLoad and that is going to be used when user clicks the search button. If the User is IDLE for more than 20 Min the value of Session is get expired. And when user clicks on Search Button. It Throws error " Object Reference Not Set To an Instance of an Object".
On PageLoad:
if (!IsPostBack)
{
Session["CaptchaImageText"] = new RandomGen().GenerateRandomCode();
}
On SearchButtonClick event:
if (SecurityCodeTextBox.Text.Trim() == Session["Captcha"].ToString())
{
return true;
}
else
{
return false;
}
Here i get error "Object Reference Not Set To an Instance of an Object".
i have also checked wheather the Session["Captcha"]!= null. But still it shows the same error.
How to Redirect or show a message that "Session Timeout !Visit again" and close the Browser.
Thanks in Advance!
Your code looks like you're inconsistent with your Session variable naming (I'm a strong proponent of constants for these).
That being said, the easiest way to handle your situation is
private void Page_Load(object sender, System.EventArgs e)
{
Response.AddHeader("Refresh",Convert.ToString((Session.Timeout * 60) + 5));
if( string.IsNullOrEmpty(Session["Captcha"] as string) )
{
Server.Transfer("RedirectPage.aspx");
}
}
That will cause a page redirect on session expiration.
TO close the browser, you need a client-side script... there is no way to do it by server-side, so, you can generate some javascript calling window.close();. For th message error, check if the Session[] is not null, if you call some method of this and it's null, you will get this kind of exception. Try something like this:
if (Session["Captcha"] == null)
{
Page.ClientScript.RegisterStartupScript(this.GetType(), "alert", "alert('Session Timeout! Visit again.'); window.close();", true);
return false;
}
return (SecurityCodeTextBox.Text.Trim() == Session["Captcha"].ToString());

Why HttpContext.Current.Session is null in Global.asax?

I'm using VS2010 and created a simple asp. web forms application, using Development Server to test it.
I try to store user data - queried from sql server - in the session, since I don't want to access database in every request. I'm using the 'Application_AuthenticateRequest' and the 'Session_Start' methods.
First round:
AuthenticateRequest called. The following code ran:
public static void Initialize(string login_name, bool force_refresh)
{
HttpSessionState Session = HttpContext.Current.Session;
object o = Session == null ? null : Session["EMPLOYEE_DATA"];
if (force_refresh || o == null || o.GetType() != typeof(Employee) || (o as Employee).login_name!= login_name)
{
_current = UIManager.GetEmployee(login_name);
if (Session != null)
{
Session["EMPLOYEE_DATA"] = _current;
}
}
else
{
_current = (Employee)o;
}
}
The _current variable is a private static field published through a static property.
In the first round the Session is null, and I think it's ok because the Session_Start not called yet.
The Session_Start looks like this:
protected void Session_Start(object sender, EventArgs e)
{
Session["EMPLOYEE_DATA"] = EmployeeFactory.Current;
}
In the next round the Session_Start is not called of course but in the AuthenticateRequest I can't access to the session. The HttpContext.Current.Session is null and the this.Session reference throw a HttpException says the "Session state is not available in this context".
However I can access the Session from any of the page_load events but it's a bad practice I think that I put authentication every page_load.
Any idea how can I access to the Session?
Thanks for advice,
Péter
You're not able to use Session on the Application_AuthenticateRequest becauase it's not bound at that moment.
I think you're able to use the event Application_AcquireRequestState.
try to use the below code in page_Load
Response.AppendHeader("Refresh", Convert.ToString(Session.Timeout * 15) + ";
URL=SessionExpPage.aspx");

Session expiration issue in ASP.NET MVC

Hi I have some issues with ASP.NET MVC session state which is not expiring after I implement the following piece of code and put the attributes over the methods.
public sealed class SessionActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpContext ctx = HttpContext.Current;
//Check if session is supported
if (ctx.Session != null)
{
//Check if the session is new
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 = filterContext.HttpContext.Request.Headers["Cookie"];
if ((sessionCookie != null) && (sessionCookie.IndexOf("ASP.NET_SessionId", StringComparison.OrdinalIgnoreCase) >= 0))
{
//Redirect to the login page
ctx.Response.Redirect("~/Home/Index", true);
ctx.Response.End();
}
}
}
base.OnActionExecuting(filterContext);
}
}
The issue is that the Redirection request is not executing and the Action which has SessionActionFilter Attribute executes. This method uses session variables which are expired and results in error.
Can anybody tell what I am missing?
Thanks a lot in advance!!
We are storing some data which is used in our views!! One more update I was able to run this piece of code which is now working fine. However, I am a bit skeptical about the use of cookies and need to transform this code to work for cookieless sessions also. How is this possible?

ASP.NET 2.0: Problem in Httpcontext.current.session.add()

Can anybody help me to find out solution of following problem.
In ASP.NET website: at Application_OnPostAuthenticate() event, whatever code i write is executed for every request. therefore due to this customidentity object, countryid and weatherid is called everytime for each request (call for database for value). It effect response time of page and unneccessary code execute.
void Application_OnPostAuthenticateRequest(object sender, EventArgs e)
{
// Get a reference to the current User
IPrincipal objIPrincipal = HttpContext.Current.User;
// If we are dealing with an authenticated forms authentication request
if ((objIPrincipal.Identity.IsAuthenticated) && (objIPrincipal.Identity.AuthenticationType == "Forms"))
{
CustomPrincipal objCustomPrincipal = new CustomPrincipal();
objCustomPrincipal = objCustomPrincipal.GetCustomPrincipalObject(objIPrincipal.Identity.Name);
HttpContext.Current.User = objCustomPrincipal;
CustomIdentity ci = (CustomIdentity)objCustomPrincipal.Identity;
HttpContext.Current.Cache["CountryID"] = FatchMasterInfo.GetCountryID(ci.CultureId);
HttpContext.Current.Cache["WeatherLocationID"] = FatchMasterInfo.GetWeatherLocationId(ci.UserId);
Thread.CurrentPrincipal = objCustomPrincipal;
}
}
To solve this problem when i try tochange code as follows
HttpContext.Current.Session.Add("test", FatchMasterInfo.GetWeatherLocationId(ci.UserId);); in place of cache i found foolowing error
"Object refrence not set to the instance of object"
I don't know whether we can store session variable inside Application_OnPostAuthenticate() event or not?
You could try doing this a bit later in the request, such as in the PreRequestHandlerExecute event:
protected void Application_PreRequestHandlerExecute(object sender, EventArgs e)
{
IPrincipal objIPrincipal = HttpContext.Current.User;
if ((objIPrincipal.Identity.IsAuthenticated) && (objIPrincipal.Identity.AuthenticationType == "Forms"))
{
HttpSessionState session = HttpContext.Current.Session;
CustomPrincipal objCustomPrincipal = new CustomPrincipal();
if (session[objIPrincipal.Identity.Name] == null)
{
// get data from database or wherever
objCustomPrincipal = objCustomPrincipal.GetCustomPrincipalObject(objIPrincipal.Identity.Name);
CustomIdentity ci = (CustomIdentity)objCustomPrincipal.Identity;
Object countryID = FatchMasterInfo.GetCountryID(ci.CultureId);
Object weatherLocationID = FatchMasterInfo.GetWeatherLocationId(ci.UserId);
// save in session (not cache as cache is application-wide, not per-user):
session.Add(objIPrincipal.Identity.Name, objCustomPrincipal);
session.Add(objIPrincipal.Identity.Name + "_CountryID", countryID);
session.Add(objIPrincipal.Identity.Name + "_WeatherLocationID", weatherLocationID);
}
else
{
// already have custom principal object in session
objCustomPrincipal = (CustomPrincipal)session[objIPrincipal.Identity.Name];
}
// set the custom principal object to context/thread
HttpContext.Current.User = objCustomPrincipal;
Thread.CurrentPrincipal = objCustomPrincipal;
}
}
You probably don't want to access the session in any event that happens in every request. Some requests don't even have session (for instance, a lot of web service calls, or calls to WebResource.axd that load static resources).
Before adding value to cache object, check if it already exists in the cache.
You might not have session state enabled. Does it work anywhere else (like in a web form's display)?
Look for a <sessionState> element under your system.web element in web.config make sure it's turned on (set it to InProc unless you have a web farm).

How to determine Session Timeout using when reusing CookieContainer

I have the following code which re-uses a CookieContainer which logs in on the first request, but just uses the cookie container for requests after.
After a period of time if idle the site will give a Session Timeout, I will need to perform the login again.
Q: Can I determine (with the cookie container object) if the timeout has happened or is it best to determine if it has happened from the HttpWebResponse which happens to contains text like 'session timeout'. What is the best way to do this?
private static CookieContainer _cookieContainer;
private static CookieContainer CurrentCookieContainer
{
get
{
if (_cookieContainer == null || _cookieContainer.Count == 0)
{
lock (_lock)
{
if (_cookieContainer == null || _cookieContainer.Count == 0)
{
//_cookieContainer.GetCookies(
_cookieContainer = DoLogin();
}
}
}
return _cookieContainer;
}
set
{
_cookieContainer = value;
}
}
And then this method calls out to the container:
public static string SomeMethod(SomeParams p)
{
HttpWebRequest request_thirdPartyEnquiryDetails = (HttpWebRequest)WebRequest.Create(thirdPartyEnquiryDetails);
CookieContainer cookieContainer = CurrentCookieContainer;
request_thirdPartyEnquiryDetails.CookieContainer = cookieContainer;
//... and it goes on to submit a search and return the response
}
Well, since the timeout is 30 mins, I have set the login to repeat after 25 mins.
private static DateTime? lastLoggedIn;
private static CookieContainer _cookieContainer;
private static CookieContainer CurrentCookieContainer
{
get
{
if (_cookieContainer == null || _cookieContainer.Count == 0 || !lastLoggedIn.HasValue || lastLoggedIn.Value.AddMinutes(25) < DateTime.Now)
{
lock (_lock)
{
if (_cookieContainer == null || _cookieContainer.Count == 0 || !lastLoggedIn.HasValue || lastLoggedIn.Value.AddMinutes(25) < DateTime.Now)
{
_cookieContainer = DoLogin();
lastLoggedIn = DateTime.Now;
}
}
}
return _cookieContainer;
}
set
{
_cookieContainer = value;
}
}
As an extra precaution, I check the HttpResponse for the text which returns when the page session times out (although its now expected this won't be seen). If this happens I set the lastLoggedIn date to null and run the search method again.
You can extract all cookies for a domain using the CookieContainer.GetCookies(string uri) method. Using this CookieCollection you can get the cookie you are interested in and check its Expired property to see if it has expired.
There is one thing you should note: Your session may end even if your cookie is valid. IIS may restart the app domain the web application runs in and in that case all authenticated users may loose their session data. So checking the cookie is generally not enough to ensure that you stay logged in.
I am not sure what you want to achieve, but you should notice that CookieContainer has a bug on .Add(Cookie) and .GetCookies(uri) method.
See the details and fix here:
http://dot-net-expertise.blogspot.com/2009/10/cookiecontainer-domain-handling-bug-fix.html

Resources