Session and Cookies in ASP.NET MVC? Oh my!
November 4, 2012 18 Comments
This post is brought to you by this post on LinkedIn (you may need to belong to the ASP.NET MVC group). The question of the day:
In MVC it bad practice to use session & cookies then what are the options to maintain session
If you understand how HTTP works, you understand this is a bad question, or at least one born out of ignorance.
Before getting into the meat, let’s examine two important concepts: synchronicity and state.
Synchronicity is whether or not we immediately get feedback. For example, if I fill out a form to join and immediately get logged on, it is a synchronous system. If, instead, I fill out the form and get a email with a link and then log in, it is asynchronous. A better example is a chat application (synchronous) versus email (asynchronous) or the difference between the chat window in Facebook (synchronous) versus either sending a Facebook message, playing words with friends or using Twitter (asynchronous).
Now to state. State is the current “data” stored about you, or something else, in the system. Oversimplification, but consider I have $1000 in the bank. The state of my account is $1000 on the positive side. If I then get $100 cash, the state is $900 in the bank. The same is true if I change my Facebook status to single (not my real status, of course, but it would be my state in the system).
How applications work (and some history)
The first applications were normally either dumb terminals (maximum statefulness and synchronicity) or client/server applications (high level of statefulness and synchronicity). When you logged in, you were connected full time to the server, so any changes were instantly reflected. Not 100% true, but it covers the general nature.
Now, let’s move up to the web. The client is not connected to the server except when making a request, making it an asynchronous and stateless system. This may take a moment to sink in, but I feel the need to disgress (ADHD popping up?) and cover how we got here.
I first got on the Internet in the late 80s through shell programs on a BBS (bulletin board system). At this point in time, you had email and newsgroups as your primary means of communication with other people. To organize information, you had Gopher. Gopher was a decent system for putting “books” on the Internet, but a bad system for user interaction.
One more step into ADHD land? :: The government (and education) started what would become the “Internet” in the late 1960s as ARPANET. They brought education in, and ultimately other countries (our allies), in the 1970s.
Now, let’s cover the WWW. Gopher was a bit of a pain to program with. But that changed when Tim Bernas-Lee took a government standard (SGML, or Standard Generalized Markup Language) and created HTML (HyperText Markup Language). The main push was to make it easier to disseminate information, but it was easy enough to create applications that were interactive. I could go deeper (will consider in another post) and get into what HyperText truly means (perhaps a post on REST?).
Now, you have a bit of background, let’s get to the core. Hypertext applications are both stateless and asynchronous. The operations in these types of applications may be synchronous (added to avoid arguments from purists), but the basic nature of the communication is asynchronous, as you
Hypertext applications work on a request and response system. You create a request and send it to the server. Prior to your request coming in, the server has no clue who you are, even if you have contacted it 20 times in the last 2 minutes. Every request is treated as a new request from an unknown entity, making it stateless. The server disconnects after the response is sent, so it is non-connected (except to handle requests) and you can take time to determine the next course of action, making it asynchronous.
Now some may argue with the last line of the last paragraph, thinking “if I am logged in, I can’t walk away for a long time; I have to fill in the form within X minutes or I have to start over”. This is true, but as long as you have some means of saving state to the server, you can pick up with the remainder of your work at any time. And, if you are not logged in, you can keep the page open, shut down your computer, and come back and click links on the page hours, or even days, later. So the basic nature of hypertext is stateless. That is our important takeaway to move to session and cookies.
Persistence is the mechanism by which state is stored until a user is ready to use it again. Long term persistence is usually handled either by a database or files. Once the user has changed something, the information is normally persisted to these long term persistent stores.
In addition to long term persistence, there is short term persistence. This is where cache comes in. Cache is persisting of state in memory. What about session? Session is a cache that includes bits to tie information to a particular user. Session also allows for expiration of cached state based on a user logging out (immediate) or timing out (end of session time). When either condition is met (log out or time out), the user specific state is cleared.
It should be noted that the main difference between a database, files, memory cache and session is where the state is stored. This is important for reliability and speed. Storing in memory fails if the machine is rebooted (or worse, the power pulled), but it is much faster to retrieve from memory than involve I/O (either pulling from disk, over the network or both).
Then what are cookies? Cookies are another form of persistence mechanism, only the information is stored on the client. The cookie may simply persist a user ID (to retrieve from session) or it may persist all of the user’s data (impractical over a certain amount of information). If it is just an ID, you need another method to pull the rest of the information, which means persistence on the server.
In Summary, for this section of this post (there are others, just not relevant):
Server Side Persistence
Files (XML or otherwise)
Client Side Persistence
Kludges, aka sessions and cookies
This may seem unfair calling these items kludges, but let’s examine. You have a stateless mechanism (web pages), as they do not hold state. The client is only connected for the length of a request and either errors or fulfills the request and then shuts it down. The request is forgotten after the response is sent.
But, you need state. So you first create a means of storing information on the client. This is the cookie. Think of a cookie as a property bag storing name/value pairs. This is sent to the client as part of the header of the response (ie, the part you don’t see in your browser). The client then stores it and sends it back with every request to this server.
But what happens if you need more information than can be stored in a cookie. Then you create an in-memory cache tied to the user via some type of session ID. If you have been paying attention, you realize the session ID is sent to the user with every request and sent back in.
The store for server cookies was designed to purge when the user left the site, but since the developer on the server side has some control, this did not always happen. The end result is while it is harder to turn off server cookies in all browsers, it is not impossible.
Are Session and Cookies bad in ASP.NET MVC?
If you have read this far, it should be obvious that session and cookies are simply a persistence mechanism between stateless requests. Are they bad? Yes and no. In many cases, cookies and session are a crutch to cover up bad architecture and design. In those cases, I would say they are bad. Overall, I would question the use of session and cookies in ASP.NET MVC, especially if you don’t truly understand the nature of Hypertext communication (and no, this session is not the 101 class).
On the original post, Ignat Andrei posted “And if it is a problem – it’s not only a MVC problem – it’s an ASP.NET problem.”. Correct, it is a problem in ASP.NET, as well. Or at least a variation of the same kludgy solution. In fact, it is a “problem” in all HTTP centered apps that allow for session (web server controlled in-memory cache) and cookies.
One of the beauties of ASP.NET MVC is you can get rid of a false reliance on the Session object and/or cookies for most of your work. Not that MVC is really that different from any other web application (it is just a pattern), but that the pattern should get you thinking in paradigms where you don’t rely on kludgy state mechanisms.
ASP.NET MVC was created due to a couple of reasons. The most obvious is Ruby on Rails, since Rails uses the MVC pattern. But another concern is pushing people towards a paradigm that encourages use of best practices, primarily separation of concerns. While the paradigm works fairly well, in many cases, you don’t solve process and people problems with technology, at least not completely.
Now back to the question of bad for session. Why would it be bad? One reason is users generally use session as a crutch to store page items. This is overcoming bad architecture with bad practices.
Another reason is session takes up space on the server. You don’t get session for free. When you use session, you take up memory and reduce scale. This is not always bad, but you do have to be aware of it. The question comes down whether scalability is an issue. The same is true of any form of in-memory cache, but you can easily switch to a distributed cache if you are using MemoryCache, by using a factory or provider pattern; you don’t have the easy configuration change type of switch going from Session to distributed (at least not without adapters) and even if you could, the purpose and pattern are different.
Another reason is IIS recycles. Not often that it screws over most of your users, but it does. Since HTTP is stateless, the user can still request pages, but now he is hosed as far as anything stuck in session goes. The same can be true of having to log back in, depending on your mechanisms, however.
Another reason is web farms. Not a big deal for the single server “share my club” type of site, but if you have a site on multiple servers, you end up with session in memory on all of the servers (at least the potential of that). ouch!
Now the comeback is “Greg, I use session state in SQL Server”. Great! Then why use session at all? If you are taking the trip to SQL Server for every hit, why incur the consumption of extra space for items that may never be requested. And why incur the extra overhead of clearing a user’s session, including the piece where you clear the data out of SQL Server. It is pure overhead at this point.
Does this mean never use session? Let’s look at that in a section entitled …
What if I feel the need to use Session in ASP.NET MVC
Did you not read the rest of this post? Okay, so there is an alternative: Use TempData instead. It is an abstraction in ASP.NET MVC on top of the old ASP.NET session. And it allows you to more easily change types of persistence. Realize this is still an abstraction on top of a kludge, but it is a useful abstraction as it is easily switched to a better method.
But you did not answer if it was bad …
As with everything in life, there is no one size fits all answer. As an example, I present adriamycin. Originally developed as an antibiotic, it was found to be too toxic. But it is rather effective on certain types of cancer, so while it is a poison, and should generally not be consumed, there are times it is the most effective path.
Read that again. What I am saying is I would generally avoid session like the plague, but there are always exceptions.
If you want a rule of thumb: Avoid the use of session to store temporary values, unless you can find no other mechanism, or the factors of developing the application make session a better option. The same can be said of storing in cookies.
The Aspects of Development and Session
All of this stems back to the aspects of development. There are five major aspects to consider:
In addition to these, time and budget have to be considered, as they are valid concerns. If using session is needed for time, for example, you may have to code it that way. But make sure there is time to remove it later if you find you are using it in a kludgy manner. The same is true of budget, but then time is money.
To figure what is best, you look at each application uniquely and determine the best mix of the aspects. If scalability is the biggest issue, you may lose some performance to better separate out concerns (monoliths run fast, but scale horribly). In financial applications, security is often the biggest concern. In general, maintainability (or the lack thereof) cost more money than any other aspect.
Session (and cookies) are often used as persistent mechanisms of convenience. They were both built as kludges to make a stateless system stateful. As such, unless you have a proper reason for using them, you should not use them. And, if you have a proper reason, you should examine it and see the proper reason is based more on familiarity than true need.
But, the above advice should be said for every architecture/design you have. You should examine all of your assumptions and ensure you have made proper decisions. Only then can you be sure things are solid (nice play on words, eh?)
Realize that the above has a caveat. You have to be able to examine within the time constraints of the project. If you can’t deliver, it does not matter how good the product is.
Peace and Grace,