I have an asp.net web app which uses state server to store its sessions. When we change a type of something which is stored in the session, all users with active sessions got error, beacuse the "old session" contains insrtances of "old type".
I thought that the simplest way to overcome this problem would be to restart the state server, therefor get rid of all sessions. However, this was proffed to be a naive approach. Sessions seems to be still active (users with session old cookie are still capable of working). Is there some other way to force the session state server throw away all sessions, so that old users will be assigned new session? It is ok if they would be forced to authenticate again.
Or is there some other (better) way of abandoning all sessions? Ideally not programmaticaly, but something our admin could do?
Programmatical approach woudl be maybe calling Session.RemoveAll in Application_End would solve the issue, bu is this standard approach?
Where are session stored in state server if not in memory (which should cease to exist on restart)?
I have found two SO questions which are relevant:
Clear all sessions on application start - this is rather incomplete programmatical solution
How to clear SQL session state for all users in ASP.NET - this is exactly what I would needed if I had had an sql server approach of storing of session data
Ok, So it seems so (after a bit of experimenting), that restarting of the session state server throw away all data in the session.
The users still have their session ID valid after restart though, which got me originally thinking that the session is not thrown away.
I guess that if the session id sent from a user is not assigned to some existing session, than it is reused for the new one, so user still operates with the same id. Nevertheless, the data in session are cleared.
This doesn't directly answer your question but a clean programmatic workaround could be to wrap access to Session and try to be smart and detect issues:
// example
public string SomethingWrapper
{
try
{
return (string)Session["something"];
}
catch
{
return "defaultvalue";
}
}
This should work for value objects and composite objects too. If the deserializer fails for a compound object, you get an exception and have a chance to return just anything, a default value for example. Or you can recreate the value and put it back into session container.
Related
To start with, this is code that I inherited and the person who wrote it is no longer here nor available to question.
I have users in production getting annoyed at randomly being logged out of our Asp.Net MVC application (According to references our MVC libraries are version 5). After flailing about in the code and website for a while I think I have isolated what users are seeing to the following bit of code:
public class SessionExpireFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
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))
{
SessionVariables.Current.User = null;
FormsAuthentication.SignOut();
filterContext.Result = new RedirectResult("~/Account/Logon");
return;
}
}
}
base.OnActionExecuting(filterContext);
}
}
I'm not totally sure why this code is needed (why would you attribute this instead of making it global) but I have seen variations of this code around the internet in my searches but not with description of why you'd want it.
Regardless, it is already in our code base and the issues that we are having seems to be that if the user is idle in a window for a small period of time and then they do something, ctx.Session is not null but ctx.Session.IsNewSession is true.
This implies to me that for some reason Asp.net decided this user needed a brand new session started up for them, and since we have no idea who this user is (since all their session data is gone since ... it's a new session) we need to log them out and make them log in again.
This all seems logical except I just finally was able to hit a breakpoint inside the IsNewSession if statement. What's odd to me is that my Session actually looks 100% filled out (and filled out correctly). This means it correctly knows who I am, and all other information that only gets put into the session when you successfully log in.
Furthermore, ctx.User.Identity.IsAuthenticated is true, and it has the correct login name.
Everything seems to point that I have a valid session, but since this code is making the design decision that if Asp.Net creates a new session I must be logged out, the user is getting logged out.
So my question is:
What does Session.IsNewSession mean in practical terms?
Is it correct to always log the user out when IsNewSession is true?
Are there any ramifications for not logging the user out as long as they are listed as authenticated and has valid session data?
What causes Asp.Net to create a new session and yet still re-use previous session data?
My understanding with session expiration was it was caused by the provider layer, in that Asp.Net wouldn't even have any session data if the session has expired. Is that not the case?
As a quick side note, we are currently using Redis as our session store. Also, if relevant the application is being hosted on Azure websites (and I'm not sure how that affects session expiration).
ASP.NET creates a new Session any time a browser without a current session navigates to the site. So even if someone isn't logged in, they'll still have a Session. Likewise, if one session expires, a new session will be created the next time the browser makes a request. This new session won't have "session data" stored in it, but ctx.Session will not be null. Also, if you have multiple servers and the load balancer happens to route the user to a different server, then that new server will try to start a new session.
Session state is tracked separately from Authentication state, meaning that one can expire while the other is still valid. For well-written applications, this typically won't cause any problems. However, some applications pre-load information into the session upon login, and treat the session as a kind of cache for this information for the length of the session. Or, they will set values on the session when the user performs certain actions, and later actions will expect those values to be on the session, because the user should have navigated through those earlier actions to get there. (e.g. a Wizard interface, where each step saves values to the session, to be used when the user clicks "Finish" on the final step.)
It's possible that your application at some point was expecting data to be on the session which wasn't there, and the developers realized it wasn't there because ASP.NET had automatically renewed the session, losing all the previously-set session data. Rather than redesigning their use of session data, they chose to make it so that any time they lose the session they'll also force the user to go back to a sane starting position, where pages won't break in weird ways just because session-stored data was lost.
I'm building a website with ASP.NET MVC3. When a user signs in, I pull their display name from the database and store it to a session variable:
Session["DisplayName"] = user.Display;
Then in _Layout.cshtml I use it to display at the top of each page:
<span class="user">#(Session["DisplayName"] as string)</span>
This works fine when I start debugging the website then log in, but if I then rebuild my server and begin debugging again, my browser remains logged in but the Session variables are cleared. This leads to a bunch of empty spaces where my display name should be.
Is this a side-effect of rebuilding the server, and not something I need to worry about in deployment? Is there a way to invalidate logins every time I rebuild, so that I avoid this issue? Or is there a better way to store this user data, other than a Session variable?
Is this a side-effect of rebuilding the server, and not something I
need to worry about in deployment?
Oh no, that's something that you absolutely should worry about. As you know ASP.NET session is by default stored in server memory. And when the AppDomain is recycled (which could happen at absolutely any time) by IIS all your session is gone. For example IIS could bring down the AppDomain after a certain inactivity on the application. Or after certain CPU or memory usage thresholds are reached. If you want to be able to reliable store something in the ASP.NET session you could offload the storage off-proc and store this session either in a dedicated session server or SQL. But honestly, I have seen many people moving ASP.NET Session to SQL Server and regretting it. What's the point? You already have this information in SQL Server :-) I once used this and regretted it so much.
Personally I never use ASP.NET Session in my applications. If you need to persist such information as the display name and avoid hitting the database at each request you could store it in the User Data section of the Forms Authentication cookie. So here's the idea: when the user successfully inputs correct credentials, you manually create a FormsAuthenticationTicket and populate its UserData property with whatever information you want to be available about this use on each request and then emit the authentication cookie. Then you write a custom Authorize attribute in which you decrypt the cookie, fetch the User Data and store it as a custom IIdentity making it available on each request.
Store usernames in cache (Cache[string.Format("DisplayName_{0}", User.Id)] = User.Username), cookies or move session to SQL Server instead of InProc
I would create a static helper method that gets username by user id. If it finds cached value, it will use that, if not, get value from db, store it in cache and return.
public static string GetUsername(int UserID)
{
string cacheKey=string.Format("DisplayName_{0}", UserID);
if (HttpContext.Current.Cache[cacheKey]==null)
{
// Retrieve user name from DB
string Username=Repository.GetUserName(UserID);
HttpContext.Current.Cache[cacheKey]=Username;
}
return HttpContext.Current.Cache[cacheKey].ToString();
}
There are better ways, but to address your specific issue your auth timeout and session timeout are not the same, you need to handle the case specifically when one will timeout before the other. See my post here:
How can I handle forms authentication timeout exceptions in ASP.NET?
I'm a little confused about the life cycle of the session in ASP.NET, here is my test case.
A user logs in, I save some info to a session variable (e.g. Session["bob"]="bob") then I do an "IIS reset". The user is still logged in, but the session data is null (e.g Session["bob"].ToString() throws a NullReferenceException.
I expected the session data to still be around. Is there something I can do, other than log out the user? I expected the session data to be around as long as the user is still logged in.
Any good links so I grok what's going on, as well as any help with the actual issue is greatly appreciated. I tried to Google this, but wasn't able to frame the question in a way to get what I wanted.
The behavior you are seeing - where the Session contents do not survive an IIS reset event - is due to where the Session values are stored. By default these values are stored within the memory of the ASP.NET "Worker Process", which is the program which runs your ASP.NET web site.
When you perform an "IIS reset" you shut down the entire IIS server, including the ASP.NET Worker Process. This means that the contents of the Session are removed from memory. Your user still appears to be logged in because that is controlled by the cookie stored in their browser. If the cookie is still valid, the login is.
If you wish your Session state to survive an IIS reset (or anything else which causes the ASP.NET worker process to restart) you'll need to store your Session objects in another place. This is fully supported by ASP.NET by using different Session storage "Modes". Read about those in the MSDN article "Session-State Modes".
For a general overview of the Session, check out the "ASP.NET Session State Overview" article on MSDN.
yah its right but some time its happen then session no remove properly at that time
you have to check session like
If Session("username") = nothing then
Response.redirect("~/default.aspx")
End if
I am wanting to store the "state" of some actions the user is performing in a series of different ASP.Net webforms. What are my choices for persisting state, and what are the pros/cons of each solution?
I have been using Session objects, and using some helper methods to strongly type the objects:
public static Account GetCurrentAccount(HttpSessionState session)
{
return (Account)session[ACCOUNT];
}
public static void SetCurrentAccount(Account obj, HttpSessionState session)
{
session[ACCOUNT] = obj;
}
I have been told by numerous sources that "Session is evil", so that is really the root cause of this question. I want to know what you think "best practice", and why.
There is nothing inherently evil with session state.
There are a couple of things to keep in mind that might bite you though:
If the user presses the browser back button you go back to the previous page but your session state is not reverted. So your CurrentAccount might not be what it originally was on the page.
ASP.NET processes can get recycled by IIS. When that happens you next request will start a new process. If you are using in process session state, the default, it will be gone :-(
Session can also timeout with the same result if the user isn't active for some time. This defaults to 20 minutes so a nice lunch will do it.
Using out of process session state requires all objects stored in session state to be serializable.
If the user opens a second browser window he will expect to have a second and distinct application but the session state is most likely going to be shared between to two. So changing the CurrentAccount in one browser window will do the same in the other.
Your two choices for temporarily storing form data are, first, to store each form's information in session state variable(s) and, second, to pass the form information along using URL parameters. Using Cookies as a potential third option is simply not workable for the simple reason that many of your visitors are likely to have cookies turned off (this doesn't affect session cookies, however). Also, I am assuming by the nature of your question that you do not want to store this information in a database table until it is fully committed.
Using Session variable(s) is the classic solution to this problem but it does suffer from a few drawbacks. Among these are (1) large amounts of data can use up server RAM if you are using inproc session management, (2) sharing session variables across multiple servers in a server farm requires additional considerations, and (3) a professionally-designed app must guard against session expiration (don't just cast a session variable and use it - if the session has expired the cast will throw an error). However, for the vast majority of applications, session variables are unquestionably the way to go.
The alternative is to pass each form's information along in the URL. The primary problem with this approach is that you'll have to be extremely careful about "passing along" information. For example, if you are collecting information in four pages, you would need to collect information in the first, pass it in the URL to the second page where you must store it in that page's viewstate. Then, when calling the third page, you'll collect form data from the second page plus the viewstate variables and encode both in the URL, etc. If you have five or more pages or if the visitor will be jumping around the site, you'll have a real mess on your hands. Keep in mind also that all information will need to A) be serialized to a URL-safe string and B) encoded in such a manner as to prevent simple URL-based hacks (e.g. if you put the price in clear-text and pass it along, someone could change the price). Note that you can reduce some of these problems by creating a kind of "session manager" and have it manage the URL strings for you but you would still have to be extremely sensitive to the possibility that any given link could blow away someone's entire session if it isn't managed properly.
In the end, I use URL variables only for passing along very limited data from one page to the next (e.g. an item's ID as encoded in a link to that item).
Let us assume, then, that you would indeed manage a user's data using the built-in Sessions capability. Why would someone tell you that "Session is evil"? Well, in addition to the memory load, server-farm, and expiration considerations presented above, the primary critique of Session variables that they are, effectively, untyped variables.
Fortunately, prudent use of Session variables can avoid memory problems (big items should be kept in the database anyhow) and if you are running a site large enough to need a server farm, there are plenty of mechanisms available for sharing state built in to ASP.NET (hint: you will not use inproc storage).
To avoid essentially all of the rest of Session's drawbacks, I recommend that implement an object to hold your session data as well as some simple Session object management capabilities. Then build these into a descendent of the Page class and use this descendent Page class for all of your pages. It is then a simple matter to access your Session data via the page class as a set of strongly-typed values. Note that your Object's fields will give you a way to access each of your "session variables" in a strongly typed manner (e.g. one field per variable).
Let me know if this is a straightforward task for you or if you'd like some sample code!
As far as I know, Session is the intended way of storing this information. Please keep in mind that session state generally is stored in the process by default. If you have multiple web servers, or if there is an IIS reboot, you lose session state. This can be fixed by using a ASP.NET State Service, or even an SQL database to store sessions. This ensures people get their session back, even if they are rerouted to a different web server, or in case of a recycle of the worker process.
One of the reasons for its sinister reputation is that hurried developers overuse it with string literals in UI code (rather than a helper class like yours) as the item keys, and end up with a big bag of untestable promiscuous state. Some sort of wrapper is an entry-level requirement for non-evil session use.
As for "Session being evil" ... if you were developing in classic ASP I would have to agree, but ASP.NET/IIS does a much better job.
The real question is what is the best way to maintain state. In our case, when it comes to the current logged in user, we store that object in Session, as we are constantly referring to it for their name, email address, authorization and so forth.
Other little tidbits of information that doesn't need any long-term persistence we use a combination of cookies and viewstate.
When you want to store information that can be accessed globally in your web application, a way of doing this is the ThreadStatic attribute. This turns a static member of a Class into a member that is shared by the current thread, but not other threads. The advantage of ThreadStatic is that you don't have to have a web context available. For instance, if you have a back end that does not reference System.Web, but want to share information there as well, you can set the user's id at the beginning of every request in the ThreadStatic property, and reference it in your dependency without the need of having access to the Session object.
Because it is static but only to a single thread, we ensure that other simultaneous visitors don't get our session. This works, as long as you ensure that the property is reset for every request. This makes it an ideal companion to cookies.
I think using Session object is OK in this case, but you should remember Session can expire if there is no browser activity for long time (HttpSessionState.Timeout property determines in how many minutes session-state provider terminates the session), so it's better to check for value existence before return:
public static Account GetCurrentAccount(HttpSessionState session)
{
if (Session[ACCOUNT]!=null)
return (Account)Session[ACCOUNT];
else
throw new Exception("Can't get current account. Session expired.");
}
http://www.tigraine.at/2008/07/17/session-handling-in-aspnet/
hope this helps.
Short term information, that only needs to live until the next request, can also be stored in the ViewState. This means that objects are serialized and stored in the page sent to the browser, which is then posted back to the server on a click event or similar. Then the ViewState is decoded and turned into objects again, ready to be retrieved.
Sessions are not evil, they serve an important function in ASP.NET application, serving data that must be shared between multiple pages during a user's "session". There are some suggestions, I would say to use SQL Session management when ever possible, and make certain that the objects you are using in your session collection are "serializable". The best practices would be to use the session object when you absolutely need to share state information across pages, and don't use it when you don't need to. The information is not going to be available client side, A session key is kept either in a cookie, or through the query string, or using other methods depending on how it is configured, and then the session objects are available in the database table (unless you use InProc, in which case your sessions will have the chance of being blown away during a reload of the site, or will be rendered almost useless in most clustered environments).
I think the "evil" comes from over-using the session. If you just stick anything and everything in it (like using global variables for everything) you will end up having poor performance and just a mess.
Anything you put in the session object stays there for the duration of the session unless it is cleaned up. Poor management of memory stored using inproc and stateserver will force you to scale out earlier than necessary. Store only an ID for the session/user in the session and load what is needed into the cache object on demand using a helper class. That way you can fine tune it's lifetime according to how often that data us used. The next version of asp.net may have a distributed cache(rumor).
Session as evil: Not in ASP.NET, properly configured. Yes, it's ideal to be as stateless as possible, but the reality is that you can't get there from here. You can, however, make Session behave in ways that lessen its impact -- Notably StateServer or database sessions.
Is it possible for ASP.NET to mix up which user is associated with which session variable on the server? Are session variables immutably tied to the original user that created them across time, space & dimension?
To answer your original question: Sessions are keyed to an id that is placed in a cookie. This id is generated using some random number crypto routines. It is not guaranteed to be unique but it is highly unlikely that it will ever be duplicated in the span of the life of a session. Even if your sessions run for full work days. It would probably take years for a really popular site to even generate a duplicate key (No stats or facts to back that up).
Having said all that it doesn't appear that your problem is with session values getting mixed up. The first thing that I would start to look at is connection pooling. ADO pools connections by default but if you request a connection with a username/password that is not in the pool it should give you a new connection. Hint that may be a performance bottleneck in the future if your site is very large. It has been a while since I worked with SQL Server, in Oracle there is a call that can be made to switch the identity of the user. I would be surprised if there was no equivalent in SQL Server. You might try connecting to your DB with a generic username/password and then executing that identity switch call before you hand back the connection to the rest of your code.
It depends on your session provider, if you have overriden the session key generation in a way that is no longer unique, then multiple users may be accessing the same session.
What behavior are you seeing? And are you sure there's no static in play with the variables you are talking about?
while anything is possible. . . .
No, unless you are storing session state in sql server or some other out of process storage and then messing with it. . .
The session is bound to a user cookie, the chances of that messing up in a normal scenario is very unlikely, however there could be issues if using distributed session state.
It's not possible. Sessions are tied to the creator.
Do you want to mix up, or do you have a case when it looks like mixed up?
More information:
I've got an app that takes the userid/password from the login page and stores it in a session variable. I plop it into my connection string for making calls to SQL Server.
When a table gets updated, we're using 'system_user' in the database to identify the 'last updated by' user. We're seeing some odd behavior in which the user we're expecting to be listed is incorrect, and it's showing someone else.
Can you pop in the debugger and see if the correct value is indeed being passed on that connection string? It would quickly help you idenfity which side the problem is on.
Also make sure that none of the connection code has static properties for connection or user, or one user may have their connection replaced with that of the most recent user before the update fires off.
My guess is that you're re-using a static field on a class to hold the connection string. Those static fields are re-used across multiple IIS requests so you're probably only ever seeing the most recently logged in user in the 'last updated by'.
BTW, unless you have a REALLY good reason for doing so then you shouldn't be connecting to the DB like this. You're preventing yourself from using connection pooling which is going to hurt performance under high loads.