How to determine Session Timeout using when reusing CookieContainer - asp.net

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

Related

Pass Authenticated Session In Another Request in ASP.NET

I am using ABCPDF.net to render my HTML to PDF pages, but I want to protect these using the current authenticated session. However, the request to get the HTML to render the PDF doesnt carry over the session, but creates a new one. I am using ASP.NET Membership, and passwigin the session ID and creating a cookie on the ASP.NET request.
var sessionId = HttpUtility.ParseQueryString(Url)["sid"];
if(sessionId != null)
{
doc.HtmlOptions.HttpAdditionalHeaders = string.Format("Cookie:
ASP.NET_SessionId={0}", sessionId);
}
I read this in ABCPDF.net documentation and am doing just that, but the request always uses a different session.
httpadditionalheaders
Do I need to pass something else, or can I do something else?
Fixed it by sending the auth cookie in the URL, and updating the cookie.
Url To Call
Url.ActionAbsolute(MVC.Events.Pools(eventId).AddRouteValue(FormsAuthentication.FormsCookieName, Request.Cookies[FormsAuthentication.FormsCookieName].Value)
Global.asax
protected void Application_BeginRequest()
{
try
{
string auth_cookie_name = FormsAuthentication.FormsCookieName;
if (HttpContext.Current.Request.Form[FormsAuthentication.FormsCookieName] != null)
{
UpdateCookie(auth_cookie_name, HttpContext.Current.Request.Form[FormsAuthentication.FormsCookieName]);
}
else if (HttpContext.Current.Request.QueryString[FormsAuthentication.FormsCookieName] != null)
{
UpdateCookie(auth_cookie_name, HttpContext.Current.Request.QueryString[FormsAuthentication.FormsCookieName]);
}
}
catch
{
}
}
void UpdateCookie(string cookieName, string cookieValue)
{
HttpCookie cookie = HttpContext.Current.Request.Cookies.Get(cookieName);
if (cookie == null)
{
cookie = new HttpCookie(cookieName);
HttpContext.Current.Request.Cookies.Add(cookie);
}
cookie.Value = cookieValue;
HttpContext.Current.Request.Cookies.Set(cookie);
}

Persisting Session to DB

My architect is wondering why we need to persist each user's session to the DB instead of just using cookies. I have never seen anyone use just cookies.
Usually I hold the Session Id in a cookie then use it to perform CRUDS on the session record keyed off the ID.
I mean I don't see how you can do session state without in proc. I've always done session state via a custom table holding routine fields like IsLoggedIn, IsClosed, IsNew, IPAddress, Browser, and so on.
Has anyone done session state on an e-commerce site without persisting it in a DB?
UPDATED
So here is kinda how we did things at another place I worked for an e-commerce site that got 500+ page hits a month:
public USession CreateNewSession(int userID)
{
string ipAddress = GetCurrentRequestIPAddress(context.Request);
USession newSession = USession.NewSession();
newSession.IpAddress = ipAddress;
newSession.UserID = customerID;
newSession.Browser = context.Request.UserAgent ?? string.Empty;
if (context.Request.UrlReferrer != null)
newSession.Referer = context.Request.UrlReferrer.ToString();
else
newSession.Referer = string.Empty;
InsertSession(newSession);
return newSession;
}
public USession CreateNewSession(int userID)
{
string ipAddress = GetCurrentRequestIPAddress(context.Request);
USession newSession = USession.NewSession();
newSession.IpAddress = ipAddress;
newSession.UserID = customerID;
newSession.Browser = context.Request.UserAgent ?? string.Empty;
if (context.Request.UrlReferrer != null)
newSession.Referer = context.Request.UrlReferrer.ToString();
else
newSession.Referer = string.Empty;
InsertSession(newSession);
return newSession;
}
public USession GetSession()
{
// existing sessionId this session?
HttpCookie cookie = context.Request.Cookies["usessionId"];
if (cookie == null || string.IsNullOrEmpty(cookie.Value))
session = CreateNewSession(0);
else
{
string sessionID = cookie.Value;
session = GetSession(sessionID);
if (session == null)
session = CreateNewSession(0);
else if (session.IsClosed > 0)
session = CreateNewSession(session.UserID);
}
if (session.LastAccessed < DateTime.Now.AddHours(-1)) session.LoggedIn = false;
if (session.LastDestination.Equals("lesson"))
session.LastDestPageDestinationID = ContextValue(context, "lessonid");
else
session.LastDestPageDestinationID = 0;
if (session.IsNew) session.FirstDestination = session.LastDestination;
SaveSession();
return session;
}
private void SaveSession()
{
session.LastAccess = DateTime.Now;
session.LastDest = string.Empty;
db.UpdateSession(session);
if (!cookieIsSet)
{
// add a session cookie for this current session
HttpCookie cookie = CreateSessionCookie("usessionId", session.SessionID, 365);
if (session.LastDest.Equals("logout", StringComparison.OrdinalIgnoreCase))
cookie.Value = string.Empty;
if (session.LastDest.Equals("lessonOrder")) return;
context.Response.SetCookie(cookie);
}
}
internal void UpdateSession(USession s)
{
using (ourConnection conn = CreateConnection("UpdateSession"))
{
conn.CommandText = #"update csession set
closed = #closed,
userID = #customerID,
lastAccess = #lastAccess,
lastDestination = #lastDest,
orderId = #OrderId,
IsloggedIn = #isLoggedIn;
conn.AddParam("#id", s.Id);
conn.AddParam("#closed", s.Closed);
conn.AddParam("#userID", s.UserID);
conn.AddParam("#lastAccess", s.LastAccess);
conn.AddParam("#firstDestination", s.FirstDestination);
conn.AddParam("#lastDestination", s.LastDestination);
conn.AddParam("#isLoggedIn", s.IsLoggedIn);
conn.AddParam("#orderID", s.OrderID);
try
{
conn.ExecuteNonQuery();
}
catch (Exception ex)
{
LogException(ex);
}
}
}
public HttpCookie CreateSessionCookie(string cookieValue, string uSessionID, double daysTillExpiration)
{
HttpCookie cookie = new HttpCookie("usessionid", uSessionID);
cookie.Expires = DateTime.Now.AddDays(daysTillExpiration);
cookie.Path = "/";
return cookie;
}
So we'd work with the USession custom object in memory throughout our code for checking for loggedIn, to force close their session, and all sorts of stuff based on their current session.
Also in our Application_Error in global.asax we would log the current sessionId for tracking purposes on error.
HttpCookie cookie = Request.Cookies["usessionid"];
if (cookie != null)
{
logger.Variables = "<b>uSessionID:</b> " + cookie.Value;
if (cookie.Value.Length > 0)
logger.USessionID = GetUSessionID(cookie.Value);
}
The ASP.NET session has 3 possible states:
Off (my preferred) - don't use any session at all
InProc - the session is stored in the memory of the web server. Fast, but not convinient if you are running in a web farm because each node of the web farm will have a different copy of the session and you might get conflicts.
Out-of-Proc - the session is stored in memory of a specially dedicated server running the ASP.NET Session state Windows service. Good for webfarms scenarios but not reliable enough as the session is still persisted in the memory of some server which might not survive crashes.
SQL Server - the session is persisted in SQL server. Very reliable and suitable for web farms. Problem is with performance. It will be slower than the previous modes as the session is now persisted in the database.
The 3 modes are covered in depth in the following article.
The mode you choose is configured in web.config and it is completely transparent to your code in which you simply use the Session["someKey"] to work with the session, it's just the underlying storage mechanism that differs.

How to get SessionID on a request where EnableSessionState="False"

I want to be able to get the SessionID of the currently authenticated session in a WebMethod function where EnableSession = false.
I cannot set EnableSession=true on this request, because another (long running) request on a different page is keeping the SessionState locked (EnableSessionState == "True" not "Readonly").
Is there a consistent way of getting the SessionID from either the ASP.NET Session cookie or the Url for cookieless sessions? I can code it myself but I would rather use a function that is already documented and tested.
Thank you very much,
Florin.
There seems to be no ASP.NET function that can do this, so I made up a hack of my own, which works... for now ;):
private string GetSessionID(HttpContext context)
{
var cookieless = context.Request.Params["HTTP_ASPFILTERSESSIONID"];
if (!string.IsNullOrEmpty(cookieless))
{
int start = cookieless.LastIndexOf("(");
int finish = cookieless.IndexOf(")");
if (start != -1 && finish != -1)
return cookieless.Substring(start + 1, finish - start - 1);
}
var cookie = context.Request.Cookies["ASP.NET_SessionId"];
if (cookie != null)
return cookie.Value;
return null;
}
HttpContext.Current.Session.SessionID

Accessing Session in background service using HttpModule

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.

Best way to determine if cookies are enabled in ASP.NET?

What is the best method for determining if a users browser has cookies enabled in ASP.NET
Set a cookie, force a redirect to some checking page and check the cookie.
Or set a cookie on every pageload, if it's not already set. For instance, I assume this is to check if cookies are supported to display a message when they try to login that they need to enable cookies. Set your login cookie to some default value for guest users if they don't have the cookie set yet. Then on your login page, check for the user cookie, and if it's not set, then display your message.
#Mattew is right the only way to find out is to set a cookie, redirect, then check it.
Here is a C# function to preform that check you can put this in your page load event:
private bool cookiesAreEnabled()
{
bool cookieEnabled = false;
if(Request.Browser.Cookies)
{
//Your Browser supports cookies
if (Request.QueryString["TestingCookie"] == null)
{
//not testing the cookie so create it
HttpCookie cookie = new HttpCookie("CookieTest","");
Response.Cookies.Add(cookie);
//redirect to same page because the cookie will be written to the client computer,
//only upon sending the response back from the server
Response.Redirect("Default.aspx?TestingCookie=1")
}
else
{
//let's check if Cookies are enabled
if(Request.Cookies["CookieTest"] == null)
{
//Cookies are disabled
}
else
{
//Cookies are enabled
cookieEnabled = true;
}
}
}
else
{
// Your Browser does not support cookies
}
return cookieEnabled;
}
You can do it in javascript also, this way :
function cookiesAreEnabled()
{
var cookieEnabled = (navigator.cookieEnabled) ? 1 : 0;
if (typeof navigator.cookieEnabled == "undefined" && cookieEnabled == 0){
document.cookie="testcookie";
cookieEnabled = (document.cookie.indexOf("test­cookie") != -1) ? 1 : 0;
}
return cookieEnabled == 1;
}
Write a cookie, redirect, see if you can read the cookie.
Well I think if we can save cookie in Global.ASAX session start and read that on page.. isnt that best way?
Essentially the same solution as meda, but in VB.NET:
Private Function IsCookieDisabled() As Boolean
Dim currentUrl As String = Request.RawUrl
If Request.Browser.Cookies Then
'Your Browser supports cookies
If Request.QueryString("cc") Is Nothing Then
'not testing the cookie so create it
Dim c As HttpCookie = New HttpCookie("SupportCookies", "true")
Response.Cookies.Add(c)
If currentUrl.IndexOf("?") > 0 Then
currentUrl = currentUrl + "&cc=true"
Else
currentUrl = currentUrl + "?cc=true"
End If
Response.Redirect(currentUrl)
Else
'let's check if Cookies are enabled
If Request.Cookies("SupportCookies") Is Nothing Then
'Cookies are disabled
Return True
Else
'Cookies are enabled
Return False
End If
End If
Else
Return True
End If
End Function
meda's c# function works though you have to change the line:
HttpCookie cookie = new HttpCookie("","");
to
HttpCookie cookie = new HttpCookie("CookieTest","CookieTest");
You can also check the value of Request.Browser.Cookies. If true, the browser supports cookies.
this is the best way
taken from
http://www.eggheadcafe.com/community/aspnet/7/42769/cookies-enabled-or-not-.aspx
function cc()
{
/* check for a cookie */
if (document.cookie == "")
{
/* if a cookie is not found - alert user -
change cookieexists field value to false */
alert("COOKIES need to be enabled!");
/* If the user has Cookies disabled an alert will let him know
that cookies need to be enabled to log on.*/
document.Form1.cookieexists.value ="false"
} else {
/* this sets the value to true and nothing else will happen,
the user will be able to log on*/
document.Form1.cookieexists.value ="true"
}
}
thanks to Venkat K

Resources