Do session variables work differently during development? - asp.net

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?

Related

Disadvantage of using session[""] in asp.net

In my project I use session to store user information ( username, password, personal image, and gender ) to be used in all pages of my project. I also use two other session to store small strings. Is there any disadvantage of using session ? also is there any risk of using session to store user password ?
Some things to take into account:
Don't store passwords. You should hash the incoming password, validate against the hash in your DB, and not hold on to it afterwards.
You should try to avoid using a write-access Session throughout the application, since you'll end up forcing asp.net to serialize incoming requests from the same session. Use read-only Session to avoid that. This could become apparent if you initiate multiple ajax calls simultaneously. More info here: https://connect.microsoft.com/VisualStudio/feedback/details/610820/session-based-asp-net-requests-are-serialized-and-processed-in-a-seemingly-inverse-order
Storing too much data in the Session could cause scalability issues, since all that information is held in memory on the server. If you switch over to SQL storage for sessions (common in webfarm/cloud deployments), then if the session is large every request on the server will have that Session data going back and forth between the server and the DB.
Content that goes into the session should be Serializable, just in case you decide to move over to a different persistent storage (such as sql server)
Using Sessions to retain information may not go well with stateless REST/WebApi endpoints (if you need to create any in the future)
Excessive use of Session for storage could make unit testing slightly more difficult (you will have to mock the Session)
By "personal image" I assume you are storing a url or such, and not an actual binary image. Avoid storing binary content. Only return the binary image file when the browser requests it, and don't store it in memory, the browser can cache that content easily.
You might also find the references linked in this answer to be useful in providing additional information: https://stackoverflow.com/a/15878291/1373170
The main problem with using Session and any machine depending properties is the scalability of the web site, so if you wanted to deploy your web site to a farm of servers then you can see the problem with depending on a machine state property since the request may be processed on different machines.
Hope that helps.

How to force state server to throw away all sessions?

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.

ASP.NET MVC4 Session state store username

I have created my first uber small webapp with MVC4. So far I used the layout stuff to layout the webapp and added some views controllers and a model to register and allow users to log in.
Once a user logged in / registered, I store its username in the session. I read this property from the session to determine if a user has been logged in or not.
Is that a bad practice? I read a lot about RESTful and stateless webapps. I kinda get the feeling that I should not save anything in my session.
e.g.
#if (string.IsNullOrEmpty(Session["User"] as string))
{
<dl>
<dt>Register</dt>
<dt>Login</dt>
</dl>
}
else
{
<dl>
<dt>#Session["User"]</dt>
<dt>Log out</dt>
</dl>
}
Q1: is this a bad practice?
Q2: is this "hack safe"? As is, is it easy to hack the current session and store a value in Session["User"] to bypass logging in?
To answer your questions:
1) In general, using session state is not bad practice, as long as you need it for your applications and you understand its implications on performance and scalability. However, in your case, if all you need to store is the user's name, then you really don't need it, if your application is using an ASP.Net membership provider, then this information is available in the User property in the MVCController base class:
var username = User.Identity.Name
There are three ways that session data can be stored: "InProc", where it is stored in the app process, "StateServer", where it is stored output process on a separate server, and "SQLServer", where it is stored in a SQL Server DB. Which one you should use depends upon if you are using a server farm, if your session needs to be durable (i.e. survive a machine reboot), and what the performance requirements are for your app (StateServer and SQLServer are less performant that InProc). More information can be found here
2) You should use SSL to protect your session data. The data sent over SSL (HTTPS) is fully encrypted, headers included (hence cookies). A good discussion on how to prevent session hijacking attacks is found here.

Alternative to ViewState

I'd like to store a few variables which will be referenced throughout lifecycle, starting with a db access in PreInit event. ViewState isn't an option, since it won't persist if saved so early during the page lifecycle. Given that data should not be altered by a user, what would be the best alternative?
You could use the Session to store your data. I am not sure on the number of users of your system, but assuming the data you want to store is small this won't be a problem.'
Also, unless you are using a SessionPageStatePersister (or another server side persister) or encrypting your ViewState it is still possible for the user to change the ViewState. It may be harder, but it is still possible. By default ViewState uses HiddenFieldPageStatePersister and it stores the ViewState in a hidden field on each page (as an encoded string). Just something worth considering.
Depending on the scope: Session or Application
Session
If you want the data stored per user
Application
If you want the data stored available for all users
You could store data in hidden fields, and if you want to obscure it, you could use some kind of encription. Of course these values would also only load in a later stage of the page lifecycle. The session object would be the obvious choice, although it's not everybody's favourite method.
Session probably wouldn't be available at PreInit, but you could store them in variables until a later page lifecycle task, and then store them in session at that time. I could be wrong about the session feature. Additionally, cache is an option but caching is not user-specific; you can make it user specific by appending their user ID or session ID.
Session is probably your best bet. We have to use the session to store some user information, but hit a bug due to accessing it too early. The bug is [HttpException]: Session state has created a session id, but cannot save it because the response was already flushed by the application." But it will often manifest as PageRequestMangerParserErrorException. Super fun hunting that down. One hackish fix is to write into your Global.asax code behind:
public Session_Start(object sender, EventArgs e)
{
string sessionId = Session.SessionID;
}
Accessing the SessionID forces the ASP.NET engine to go build the session before it normally would, making it possible to use it early.
Outside of session (or application) you have two other options: client storage and persistent storage. The latter is a fancy way of saying "stuff it in the database", though similar alternatives exist, of course.
Client Storage is like viewstate, but more controlled. You can use hidden fields or cookies. In fact, a cookie might work out well for you, but you'll need to encrypt the information in it if you want the user to leave it alone. Regardless, anything you send to the client you must assume is compromised, so always do a validity check.

In ASP.NET, is it OK to store user-specific data in profile with a caching mechanism rather than in session?

I have been reading articles about state management in ASP.NET for few days for my web application.
In this application, one user can create/save/execute queries, and I need to keep each parameter of a query before the user can save the query.
These parameters are string values, but the global size for one user may exceed few megabytes.
We plan to have our website running w/ ~100 users simultaneously.
In these conditions, I believe that it will not be good to store these values in session w/ in-proc mode.
We already implemented a ProfileProvider:SqlProfileProvider, using a caching mechanism and with AutoSave=true.
What is the best solution: storing these values in profile or in session but in an SQL database?
The best solution depends on whether you plan to grow beyond a single server. In a load balanced configuration, InProc session state won't work correctly (without using sticky sessions, which presents other problems). Out of proc session state, such as State Server or SQL Server, requires that your state information be serialized and deserialized for each page access. With multiple MB per user, that could be very slow.
Cache is another option, as suggested by Dave. One issue there might be whether the cache needs to be kept in sync from one web server to another.
The usual approach to this kind of problem is to store the data in the DB and in Cache, and to only retrieve it for those pages where it's really needed (unlike Session, which is read for every page). Then use SqlDependency or SqlCacheDependency to cache the data in a way that it can be updated on multiple servers if the DB changes.
Depends on your server memory and how concerned you are about it. A database is always nice for this type of thing because you have better concurrency and more stable method for storing your data.
My recommendation is that you use a sliding expiration on the cached data, say 10-20 minutes or so. That way, you won't be consuming so many server resources because as users become inactive their session data will be evicted.
For an example of how to do sliding expiration caching (also referenced here), you can do this:
public static void AddToCache(string key, Object value, int slidingMinutesToExpire)
{
if (slidingMinutesToExpire == 0)
{
HttpRuntime.Cache.Insert(key, value, null, System.Web.Caching.Cache.NoAbsoluteExpiration, System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.NotRemovable, null);
}
else
{
HttpRuntime.Cache.Insert(key, value, null, System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(slidingMinutesToExpire), System.Web.Caching.CacheItemPriority.NotRemovable, null);
}
}
1) One can keep session as Out Of Proc (on SQL Server), so the question is more about where to keep them: in memory or in database. If you keep in memory, then it will be destroyed eventually automatically. If you keep in database, then you can use this data across sessions. Decide whether you need these parameters to be saved across sessions (user can switch computers; user can open your application once in a while) - does he need these parameters to be kept for him?
2) Think about optimization - few megabytes of parameters per user?!? If that means that user can have hundreds of queries and they should be available next time user logs into the system, then keep all that in the database.
We've had some level of success persisting user details to disk to keep it out of memory. When you want something specific you then have to read it back into memory and this can be a bit slow, but it works.
For instance, you can serialize some of the objects and write them to files on the web server's hard drive. Name the files according the session ID, username, whatever, and then you can read/write from/to the files as and when you need it.

Resources