Session Management
HTTP forgets you between requests. Session state gives each visitor a private locker on the server — perfect for a shopping cart, dangerous if you fill it with everything.
On this page · 6 min · Intermediate
On this page
- Learning objectives
- Explanation
- Syntax
- Code example
- Step by step
- Real-world use
- Common mistakes
- Best practices
- Remember this
- Practice exercise
- Mini quiz
- Related topics
- My notes
- Reading time
- 6 min
- Difficulty
- Intermediate
- Updated
- Oct 29, 2026
Related tutorials
Learning objectives#
- Store and read per-user data with Session
- Explain how the session cookie links requests
- Choose a session mode for one server or a web farm
- Clear a session on logout
Explanation#
Session["Cart"] = cart stores an object for the current visitor. ASP.NET gives each browser a random id in the ASP.NET_SessionId cookie and keeps the data on the server under that id.
Values come back as object, so cast them: var cart = Session["Cart"] as List<CartLine> ?? new List<CartLine>(). A missing key returns null.
Sessions expire after 20 minutes without requests by default (sessionState timeout in Web.config). Session.Remove("Cart") removes one value; Session.Abandon() ends the whole session, for example on logout.
InProc mode (the default) keeps data in the web server’s memory: fast, but lost when the app pool recycles and not shared between servers. StateServer and SQLServer modes store it outside the process, so objects must be [Serializable].
Session requests from the same user are processed one at a time (session locking). Long requests make other tabs wait; mark read-only controllers with [SessionState(SessionStateBehavior.ReadOnly)].
Syntax#
Session["Cart"] = cart; // store
var cart = Session["Cart"] as List<CartLine>; // read (null if missing)
Session.Remove("Cart"); // remove one value
Session.Abandon(); // end the session
Code example: A session-based shopping cart#
// Models/CartLine.cs
using System;
namespace ShopSite.Models
{
[Serializable] // required for StateServer / SQLServer modes
public class CartLine
{
public string Product { get; set; }
public int Quantity { get; set; }
}
}
// Controllers/CartController.cs
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using ShopSite.Models;
namespace ShopSite.Controllers
{
public class CartController : Controller
{
private const string CartKey = "Cart";
private List<CartLine> GetCart()
{
var cart = Session[CartKey] as List<CartLine>;
if (cart == null)
{
cart = new List<CartLine>();
Session[CartKey] = cart;
}
return cart;
}
[HttpPost]
public ActionResult Add(string product)
{
var cart = GetCart();
var line = cart.FirstOrDefault(l => l.Product == product);
if (line == null) cart.Add(new CartLine { Product = product, Quantity = 1 });
else line.Quantity++;
return RedirectToAction("Index");
}
public ActionResult Index()
{
var cart = GetCart();
var lines = cart.Select(l => quot;{l.Product} x{l.Quantity}");
return Content(quot;Cart ({cart.Sum(l => l.Quantity)} items): {string.Join(", ", lines)}", "text/plain");
}
[HttpPost]
public ActionResult Clear()
{
Session.Abandon();
return RedirectToAction("Index");
}
}
}
POST /Cart/Add product=Gel+Pen 302 Found → /Cart POST /Cart/Add product=Notebook 302 Found → /Cart POST /Cart/Add product=Gel+Pen 302 Found → /Cart GET /Cart 200 OK Cart (3 items): Gel Pen x2, Notebook x1 POST /Cart/Clear 302 Found → /Cart GET /Cart 200 OK Cart (0 items):
This example is illustrative. Copy or download it and run it in your own environment; the expected output is shown above.
Step-by-step explanation#
- The first POST creates a session: the response sets the ASP.NET_SessionId cookie and the cart list is stored under "Cart".
- The browser sends the cookie back with every request, so later requests find the same cart and add to it.
- Adding Gel Pen again increases its quantity because the stored list object is updated in place.
- Clear calls Session.Abandon(); at the end of that request the session data is thrown away, and the next request starts with an empty cart.
Real-world use case#
A small online bookshop on a single IIS server keeps carts in InProc session. When it grows to two load-balanced servers, carts randomly vanish — the fix is moving session to SQL Server mode (or storing carts in the database keyed by user).
Common mistakes#
Whole product lists or DataTables in session use memory for every visitor and slow down out-of-process modes. Store ids and small DTOs.
Each server has its own memory, so a user bouncing between servers loses their session. Use StateServer, SQLServer or sticky sessions.
Session["UserId"] is not a login system: it has no protection against fixation and no expiry rules of its own. Use Forms or OWIN cookie authentication.
Best practices#
- Wrap session access in one helper with constant keys
- Keep session data small and [Serializable]
- Use out-of-process modes on web farms
- Call Session.Abandon() on logout
Remember this#
Session = per-visitor server locker, keyed by a cookie.
InProc is fast but lost on recycle and not shared.
Cast on read; null means missing.
Practice exercise#
Your task: Count how many pages a visitor has viewed in this session and show “Page views: N”.
Need a hint?
Show solution
// Controllers/VisitsController.cs
using System.Web.Mvc;
namespace ShopSite.Controllers
{
public class VisitsController : Controller
{
public ActionResult Index()
{
var views = (Session["Views"] as int? ?? 0) + 1;
Session["Views"] = views;
return Content(quot;Page views: {views}", "text/plain");
}
}
}
GET /Visits 200 OK Page views: 1 GET /Visits 200 OK Page views: 2 GET /Visits 200 OK Page views: 3
Mini quiz#
How does ASP.NET know which session belongs to a request?
Want more? Practise all ASP.NET MVC MCQs · ASP.NET MVC interview questions
My notes#
Saved in this browser.