We have a multi-layered Asp.NET Web Forms application. The data layer has a class called DataAccess which impements IDisposable and has an instance of our Entity Framework Object Context as a private field. The class has a number of public methods returning various collections of Entities and will dispose its Object Context when it is disposed.
Due to a number of problems we've been facing, we decided it would be a big plus to keep the Object Context (or an instance of DataAccess) in scope for longer on the server. A suggestion was made to keep an instance in the HttpContext.Current.Items collection from this post in order to have one instance per Http request.
What I'm wondering is: What issues / concerns / problems would arise from storing an instance of our Object Context in the HttpContext.Current.Session object????
I'm assuming that the Session object is finalised and set for garbage collection when a user's session expires, so the instance will be disposed properly.
I'm assuming most default browser settings will let our app place its SessionId cookie without qualms.
The amount of data the Object Context will be dealing with is not enormous and will not pose a problem for our decent server hardware, with regards to caching over time and relatively few concurrent users.
This will be relatively quick to implement and will not affect our many existing unit tests.
We'll be using AutoFac and a ServiceProvider class to supply instances. When an instance of the ObjectContext is required it will be returned by code similar to this:
private static Entities GetEntities(IContext context)
{
if (HttpContext.Current == null)
{
return new Entities();
}
if (HttpContext.Current.Session[entitiesKeyString] == null)
{
HttpContext.Current.Session[entitiesKeyString] = new Entities();
}
return (Entities)HttpContext.Current.Session[entitiesKeyString];
}
Cheers.
Storing an ObjectContext in the session state is not something I would consider to be a good practice since the class is intended to encapsulate a unit-of-work pattern - you load up some data (entities), modify them, commit your changes (which are tracked by the UOW), and then you're done with it. UOW objects are not intended or designed to be long-lived.
That said, it can be done without causing any major catastrophes, you just have to make sure you understand what's going on behind the scenes. Please read on if you plan on doing this so that you know what you're getting yourself into and are aware of the trade-offs.
I'm assuming that the Session object is finalised and set for garbage collection when a user's session expires, so the instance will be disposed properly.
This is actually inaccurate, or at least seems to be based on the way it's worded. Session expiry/logout will not immediately cause any of the items to be disposed. They will eventually be finalized/disposed but that is up to the garbage collector and you have no control over when it happens. The biggest potential problem here is if you happen to manually open a connection on the ObjectContext, which won't get closed automatically - if you're not careful, you could end up leaking database connections, something that wouldn't be uncovered with regular unit tests/integration tests/live tests.
The amount of data the Object Context will be dealing with is not enormous and will not pose a problem for our decent server hardware, with regards to caching over time and relatively few concurrent users.
Just keep in mind that the growth is unbounded. If a particular user decides to use your site for 12 straight hours running different queries all day then the context will just keep getting bigger and bigger. An ObjectContext doesn't have its own internal "garbage collection", it doesn't scavenge cached/tracked entities that haven't been used for a long time. If you're sure that this isn't going to be a problem based on your use cases then fine, but the main thing that should be bothering you is the fact that you lack control over the situation.
Another issue is thread-safety. ObjectContext is not thread-safe. Session access is normally serialized, so that one request will block waiting for its session state until another request for the same session is complete. However, if somebody decides to make optimizations later on, specifically the optimization of page-level read-only sessions, requests will no longer hold an exclusive lock and it would be possible for you to end up with various race conditions or re-entrancy problems.
Last but not least is of course the issue of multi-user concurrency. An ObjectContext caches its entities forever and ever until it is disposed. If another user changes the same entities on his own ObjectContext, the owner of the first ObjectContext will never find out about that change. These stale data problems can be infuriatingly difficult to debug, because you can actually watch the query go to the database and come back with fresh data, but the ObjectContext will overwrite it with the old, stale data that's already in the cache. This, in my opinion, is probably the most significant reason to avoid long-lived ObjectContext instances; even when you think you've coded it to grab the most recent data from the database, the ObjectContext will decide that it's smarter than you and hand you back the old entities instead.
If you're aware of all of these issues and have taken steps to mitigate them, fine. But my question would be, why exactly do you think that a session-level ObjectContext is such a great idea? Creating an ObjectContext is really a very cheap operation because the metadata is cached for the entire AppDomain. I'd wager a guess that either you're under the mistaken impression that it's expensive, or you're trying to implementing complicated stateful processes over several different web pages, and the long-term consequences of the latter are far worse than any specific harm you may do by simply putting an ObjectContext into the session.
If you're going to go ahead and do it anyway, just make sure you're doing it for the right reasons, because there aren't a whole lot of good reasons to do this. But, as I said, it's definitely possible to do, and your app is not going to blow up as a result.
Update - for anyone else considering downvoting this because "multiple requests on the same session could cause thread-safety issues", please read the bottom of the ASP.NET Session State Overview documentation. It is not just individual accesses of the session state that are serialized; any request that acquires a session keeps an exclusive lock on the session that is not released until the entire request is complete. Excepting some of the optimizations I listed above, it is impossible in the default configuration for there to ever be two simultaneous requests holding references to the same session-local instance of an ObjectContext.
I still wouldn't store an ObjectContext in the session state for several of the reasons listed above, but it is not a thread-safety issue unless you make it one.
You should use one ObjectContext per request, you shouldn't store it is Session. It is easy to ruin data in ObjectContext stored for a long time:
What if you insert data that don't violate rules in ObjectContext, but violate rules in database? If you insert a row that violates the rules, will you be deleting it from context? Image situation: You use one context and suddenly you have request that changes data in one table, adds row to another table, then you call SaveChanges(). One of changes throws constraint violation error. How do you clean it up? Cleaning context is not easy, it is easier just to get new one in next request.
What if someone deletes data from database, while it is still in context? ObjectContext caches data and doesn't look from time to time to check if it is still there or if they changed:)
What if someone changes web.config and Session is lost? It seems as if you want to rely on Session to store information about logged in user. Forms authentication cookie is more reliable place to store this information. Session can be lost in many situations.
ObjectContext was designed to be short lived, it is best to create it in request when needed and dispose at the end of it.
If context per request doesn't work for you, you are propably doing something wrong, but don't make it worse by using Session.
Related
What's the best way to cache web site user data in asp.net 4.0?
I have a table of user settings that track all kinds of user or session specific stuff like the state of UI elements (open/closed), preferences, whether some dialog has been dismissed, and so on. Since these don't change very often (for each user, anyway) but are looked up frequently it seems sensible to cache them. What's the best way? These are the options I've identified...
Store them in HttpContext.Current.Session directly (e.g. Session["setting_name"])
Store them in HttpContext.Current.Cache
Use a global static dictionary, e.g. static ConcurrentDictionary<string,string> where the key is a unique userID + setting name value
Store a dictionary object for each session in Session or Cache
What's the most sensible way to do this? How does Session differ from Cache from a practical standpoint? Would it ever make sense to store a dictionary as a single session/cache object versus just adding lots of values directly? I would think lookups might be faster, but updates would be slower since I'd have to re-store the entire dictionary when it changed.
What problems or benefits might there be to using a global static cache? Seems like this would be the fastest, but I'd have to manage the size. I could just flush it periodically if it hits a certain size, or keep a cross reference queue and remove things oldest first when it gets to a certain size. Does this make any sense or is it just trying too hard?
Session may end up being stored out-of-process or in a database, which can make retrieving it expensive. You would likely be using a session database if your application is to be hosted in a server farm, as opposed to a single server. A server farm provides improved scalability and reliability, and it's often a common deployment scenario. Have you thought about that?
Also, when you use Session not in-process, it ends up getting serialized to be sent out-of-process or to a database, and deserialized when retrieved, and you are effectively doing what you describe above:
... updates would be slower since I'd have
to re-store the entire dictionary when
it changed. ...
.. since, even if you use individual session keys, the entire Session object for a user is serialized and deserialized together (all at once).
Whereas, Cache would be in memory on a particular server in the farm, and therefore much more efficient than going out of process or to the database. However, something in cache on one server might not be in cache on another. So if a user's subsequent request is directed to another server in the farm, the cache on that server might not yet hold any of the user's items.
Nevertheless, I'd suggest you use Cache if you're caching for performance reasons.
p.s. Yes, you're trying too hard. Don't reinvent the wheel unless you really need to. :-)
might be better to put your information into memcached for scalability
If I have an object which works as a repository with Save(), GetProduct(prod id) etc, is it a good idea for this to be a singleton in an asp.net applications.
My thought is that because I have many accesses to the database, this would improve performance because it doesn't waist time recreating the repository object each time.
I haven't seen anything like this in any samples, so why is this wrong?
Thanks
Just be carreful that a singleton in ASP .net means that all users of your web site will use it to access data. That means that you will probably have to lock you methods and that could results in bottlenecks.
I remember that one time I had a real strange bug with singleton data manager in an ASP app.
If you don't want to recreate your repo each time a user request a page, you can also put you data repository object in the user session.
Unfortunately it really depends on how you access your Database, and how your repository class is really abstracting database connections, and transactions.
If you're just talking about the expenses of creating an in memory object for every http request then it's not a big deal. It's really not worth consideration.
If you're talking about low level database stuff, then again, it depends.
Particularly with ORMs like Linq to SQL or NHibernate, how you manage their sessions is quite important. Usually though you wouldn't want a "session's" or "datacontext's" scope to go beyond the http request, so no, a singleton wouldn't be a good idea IF the singleton is holding the DB Session as a singleton itself.
Consider using an IoC Container also, like Castle Windsor. Then to change a particular classe's "lifestyle" (singleton, transient, per web request, etc.) is a simple configuration change, and makes your application a bit more flexible.
Also, talking to the DB itself is more expensive that creating new objects in memory, so if you're really after performance consider clever caching.
Lastly, when considering Singletons, think about it from a conceptual point of view instead of performance. Does it make sense that this object be Singleton?
I'm using ASP.NET's in-process session state store. It locks access to a session exclusively, and which means concurrent requests to the same session are served sequentially.
I want to remove this implicit exclusive lock, so multiple requests per session can be handled concurrently. Of course, I'll be synchronizing access to the session state myself where it's applicable.
I'm using the MSDN documentation of Session State Providers to write my own session state provider, and this SO question pointed me to this example code of implementing this as an HTTP module, but the code looks suspiciously complex just for the purpose of removing the lock.
I should probably eventually implement the session state using ASP.NET's cache, and stop using the built-in session, like Vivek describes in this post, but for now how would I just like to remove the locking.
Any ideas or sample implementations?
Not the answer you're looking for, but I think that even if it were possible, changing the way SessionState works in this way is a terrible idea.
Think of the poor guys who will have to maintain your code down the line. The fact that Session serializes requests in this way means ASP.NET developers often don't need to worry too much about thread-safety.
Also if someone adds a third-party component that happens to use Session, it will expect the usual guarantees regarding locks - and you'll suddenly start getting Heisenbugs.
Instead, measure performance and identify specific areas where you need requests to process concurrently - I bet there'll be few of them - and carefully implement your own locking mechanism only for the specific items involved - possibly the solution that you're planning eventually using the ASP.NET cache.
If you are only reading from the session on a given page you could use the Page directive:
<%# Page EnableSessionState="ReadOnly" %>
to indicate the readonly nature and remove the exclusive write lock which will allow concurrent requests to this page from the same session.
As internally a ReaderWriter lock is used a reader lock will block a writer lock but a reader lock won't block reader lock. Writer lock will block all reader and writer lock.
If you need to both read and write from the same page to the session I think that what you've already found as information is more than sufficient. Just a remark about replacing the Session with Cache: while session is reliable, cache is not meaning that if you put something into the cache you are not guaranteed to retrieve it back. The ASP.NET could decide to evict the cache under some circumstances like low memory pressure so you always need to check if an item exists in the cache before accessing it.
but the code looks suspiciously complex just for the purpose of removing the lock.
That's because you are thinking of it as a simple lock someone added by chance / or laziness, instead of a factor that was considered in the whole session provider concept. That code looks simple enough for the task at hand / replacing the whole existing provider with your own / and while doing so lock in a different way than it is intended.
I suggest you read a bit more about how the session concept works in asp.net. Consider that the way it was designed involves reading the Whole Session once in the request, and then writing the changed session once.
Also note that while its not your scenario, code might depend on reading separate session values to process something and can write separate values as well / locking individually can get you into the same considerations that can cause a dead lock in databases.
The designed way contrasts with your intent of reading/writing+locking as each separate item is loaded/stored.
Also note that you might be updating the values of an object you retrieved from the session and not setting it back to it, yet the session was updated. As far as I know, the providers write everything in the session back at a certain point in the life cycle, so its not straightforward if you want to separate read vs. write locks at an item level.
Finally, if you are finding a high level of resistance from the framework session providers model and the way you intent to modify it will prevent you from using some features of it (as switching to a diff provider, since those would have the same issue); then I think you should just stay away from it and roll your own for your very specific needs. That's without even using asp.net Cache, since you want to it to be your way, you control the lifetime & locks of what's stored in there.
It just appears to me that you need a different mechanism altogether, so I don't see the benefit of trying to bend the framework to do so. You might reuse some very specific pieces, like generating a session id / and cookie vs. cookie-less, but other than that its a different beast.
You will have to write your own Session State Provider, it is not that hard as it seems. I wouldn't recommend you to use Cache because as Darin said Cache is not reliable enough, for example items there expire and/or removed from cache when there is not enough memory.
In your Session Store Provider you can lock items of session instead of the whole Session state (which suits us in our project) when writing, the essential code for this should be in ISessionStateItemCollection's implementation (in indexer), something like this:
public object this[string name]
{
get
{
//no lock, just returning item (maybe immutable, it depends on how you use it)
}
set
{
//lock here
}
}
For our project we have created implementation which stores items in AppFabric Cache and rely on GetAndLock, PutAndUnlock methods of the cache. If you have in-proc Session then you might just need to lock(smthg) {}
Hope this helps.
I suggest that you look into moving your sessions into SQL Server Mode. SQL Server sessions is to allow for any number of requests from multiple web servers to share a single session. As far as I know, the SQL Server manages the locking mechanism internally which is tremendously efficient. You also have the added bonus of having a lower in-memory footprint. And you don't need to write an HttpModule to run it.
I recently came across a ASP 1.1 web application that put a whole heap of stuff in the session variable - including all the DB data objects and even the DB connection object. It ends up being huge. When the web session times out (four hours after the user has finished using the application) sometimes their database transactions get rolled back. I'm assuming this is because the DB connection is not being closed properly when IIS kills the session.
Anyway, my question is what should be in the session variable? Clearly some things need to be in there. The user selects which plan they want to edit on the main screen, so the plan id goes into the session variable. Is it better to try and reduce the load on the DB by storing all the details about the user (and their manager etc.) and the plan they are editing in the session variable or should I try to minimise the stuff in the session variable and query the DB for everything I need in the Page_Load event?
This is pretty hard to answer because it's so application-specific, but here are a few guidelines I use:
Put as little as possible in the session.
User-specific selections that should only last during a given visit are a good choice
often, variables that need to be accessible to multiple pages throughout the user's visit to your site (to avoid passing them from page to page) are also good to put in the session.
From what little you've said about your application, I'd probably select your data from the db and try to find ways to minimize the impact of those queries instead of loading down the session.
Do not put database connection information in the session.
As far as caching, I'd avoid using the session for caching if possible -- you'll run into issues where someone else changes the data a user is using, plus you can't share the cached data between users. Use the ASP.NET Cache, or some other caching utility (like Memcached or Velocity).
As far as what should go in the session, anything that applies to all browser windows a user has open to your site (login, security settings, etc.) should be in the session. Things like what object is being viewed/edited should really be GET/POST variables passed around between the screens so a user can use multiple browser windows to work with your application (unless you'd like to prevent that).
DO NOT put UI objects in session.
beyond that, i'd say it varies. too much in session can slow you down if you aren't using the in process session because you are going to be serializing a lot + the speed of the provider. Cache and Session should be used sparingly and carefully. Don't just put in session because you can or is convenient. Sit down and analyze if it makes sense.
Ideally, the session in ASP should store the least amount of data that you can get away with. Storing a reference to any object that is holding system resources open (particularly a database connection) is a definite scalability killer. Also, storing uncommitted data in a session variable is just a bad idea in most cases. Overall it sounds like the current implementation is abusively using session objects to try and simulate a stateful application in a supposedly stateless environment.
Although it is much maligned, the ASP.NET model of managing state automatically through hidden fields should really eliminate the majority of the need to keep anything in session variables.
My rule of thumb is that the more scalable (in terms of users/hits) that the app needs to be, the less you can get away with using session state. There is, however, a trade-off. For web applications where the user is repeatedly accessing the same data and typically has a fairly long session per use of the site, some caching (if necessary in session objects) can actually help scalability by reducing the load on the DB server. The idea here is that it is much cheaper and less complex to farm the presentation layer than the back-end DB. Of course, with all things, this advice should be taken in moderation and doesn't apply in all situations, but for a fairly simple in-house CRUD app, it should serve you well.
A very similar question was asked regarding PHP sessions earlier. Basically, Sessions are a great place to store user-specific data that you need to access across several page loads. Sessions are NOT a great place to store database connection references; you'd be better to use some sort of connection pooling software or open/close your connection on each page load. As far as caching data in the session, this depends on how session data is being stored, how much security you need, and whether or not the data is specific to the user. A better bet would be to use something else for caching data.
storing navigation cues in sessions is tricky. The same user can have multiple windows open and then changes get propagated in a confusing manner. DB connections should definitely not be stored. ASP.NET maintains the connection pool for you, no need to resort to your own sorcery. If you need to cache stuff for short periods and the data set size is relatively small, look into ViewState as a possible option (at the cost of loading more bulk onto the page size)
A: Data that is only relative to one user. IE: a username, a user ID. At most an object representing a user. Sometimes URL-relative data (like where to take somebody) or an error message stack are useful to push into the session.
If you want to share stuff potentially between different users, use the Application store or the Cache. They're far superior.
Stephen,
Do you work for a company that starts with "I", that has a website that starts with "BC"? That sounds exactly like what I did when I first started developing in .net (and was young and stupid) -- I crammed everything I could think of in session and application. Needless to say, that was double-plus ungood.
In general, eschew session as much as possible. Certainly, non-serializable objects shouldn't be stored there (database connections and such), but even big, serializable objects shouldn't be either. You just don't want the overhead.
I would always keep very little information in session. Sessions use server memory resources which is expensive. Saving too many values in session increases the load on server and eventualy the performance of the site will go down. When you use load balance servers, usage of session can run into problems. So what I do is use minimal or no sessions, use cookies if the information is not very critical, use hidden fields more and database sessions.
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.