Tutorials ASP.NET Core MVC Mastery

Cookies & Sessions

On this page

State Management: Session & Cookies in ASP.NET Core

HTTP is a stateless protocol. It has amnesia — a server does not remember you from request 1 to request 2. To build applications with shopping carts, multi-step wizards, and user preferences, we must manage "State". Understanding the technical difference between Cookies and Session State is crucial for application architecture and security.

1. Cookies vs Session: The Absolute Truth

Cookies (Client-Side State)

Data is stored entirely on the user's browser as text strings. Sent back to the server with every HTTP request.

  • Storage: User's Browser
  • Capacity: Extremely limited (~4KB total per domain)
  • Security: Visible to user, spoofable (unless encrypted/HttpOnly)
  • Use Case: Preferences (Dark mode), anti-forgery tokens, tracking identifiers.
Session (Server-Side State)

Data is stored on the server's memory or database. The server sends a single, tiny encrypted Cookie to the browser containing just a "SessionID".

  • Storage: Server Memory (or Redis/SQL Server)
  • Capacity: Theoretically unlimited
  • Security: Highly secure — data never leaves the server
  • Use Case: Shopping carts, multi-step forms, sensitive user context.

2. Implementing Cookies

Cookies do not require any middleware setup. You access them directly via the HttpContext.

Setting and Getting Cookies

public class PreferencesController : Controller
{
    public IActionResult SetTheme()
    {
        // 1. Create secure options
        var options = new CookieOptions
        {
            Expires = DateTimeOffset.UtcNow.AddYears(1),  // Persistent cookie
            HttpOnly = false, // True blocks JS access. False allows JS (like UI theme switchers)
            Secure = true,    // Only transmit over HTTPS
            SameSite = SameSiteMode.Strict // Prevents CSRF leak
        };

        // 2. Append to response
        Response.Cookies.Append("UserTheme", "Dark", options);
        return Content("Theme Saved");
    }

    public IActionResult ReadTheme()
    {
        // 3. Read from incoming request
        string theme = Request.Cookies["UserTheme"] ?? "Light";
        return Content($"Current theme is {theme}");
    }

    public IActionResult DeleteTheme()
    {
        // 4. Browsers delete cookies when you set an expired date
        Response.Cookies.Delete("UserTheme");
        return Content("Cookie deleted");
    }
}

3. Implementing Session State

Session requires configuring the server to allocate memory and tracking identifiers.

Step 1: Configuration in Program.cs

// 1. Add Distributed Memory Cache (Session backing store)
builder.Services.AddDistributedMemoryCache();

// 2. Add Session Services
builder.Services.AddSession(options =>
{
    options.IdleTimeout = TimeSpan.FromMinutes(20); // Absolute expiration upon inactivity
    options.Cookie.HttpOnly = true;                 // Highly secure, no JS access
    options.Cookie.IsEssential = true;              // Bypasses GDPR consent for essential auth flows
    options.Cookie.Name = ".MyApp.Session";
});

var app = builder.Build();

// 3. IMPORTANT: UseSession MUST be between UseRouting and UseEndpoints/MapControllers
app.UseRouting();
app.UseSession(); 
app.UseAuthorization();

Step 2: Basic Session Usage

public class ShoppingCartController : Controller
{
    public IActionResult AddItem()
    {
        // ISession only supports Int32 and String natively
        HttpContext.Session.SetInt32("CartCount", 1);
        HttpContext.Session.SetString("LastItem", "Laptop");
        
        return Ok();
    }

    public IActionResult ViewCart()
    {
        int count = HttpContext.Session.GetInt32("CartCount") ?? 0;
        string item = HttpContext.Session.GetString("LastItem");
        
        // Remove item
        HttpContext.Session.Remove("LastItem");
        
        // Destroy entire session
        HttpContext.Session.Clear();
        
        return Ok();
    }
}

Step 3: Storing Complex Objects in Session (Production Standard)

Because ISession only accepts strings, you must serialize complex C# objects (like a full Cart) into JSON strings, and deserialize them upon retrieval.

// Extensions/SessionExtensions.cs
using System.Text.Json;
using Microsoft.AspNetCore.Http;

public static class SessionExtensions
{
    public static void SetObjectAsJson<T>(this ISession session, string key, T value)
    {
        session.SetString(key, JsonSerializer.Serialize(value));
    }

    public static T GetObjectFromJson<T>(this ISession session, string key)
    {
        var value = session.GetString(key);
        return value == null ? default : JsonSerializer.Deserialize<T>(value);
    }
}
// Controller Usage
public IActionResult Checkout()
{
    var myCart = new ShoppingCart { Items = 3, Total = 450.50m };
    
    // Save Complex Object
    HttpContext.Session.SetObjectAsJson("ActiveCart", myCart);
    
    // Retrieve Complex Object
    var retrievedCart = HttpContext.Session.GetObjectFromJson<ShoppingCart>("ActiveCart");
    
    return Ok();
}

4. Production Architecture: Distributed Caching

Web Farm Warning: In-Memory Session Limitations

builder.Services.AddDistributedMemoryCache() stores session data in the Local RAM of the web server. If your app is balanced across 3 servers (Server A, B, C), a user might save their cart on Server A. If their next click routes to Server B, their cart is utterly empty.

In enterprise production, you MUST use a distributed cache like Redis or SQL Server so all web servers access the identical session state.

// Program.cs — Enterprise Redis Registration
dotnet add package Microsoft.Extensions.Caching.StackExchangeRedis

builder.Services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = builder.Configuration.GetConnectionString("RedisUrl");
    options.InstanceName = "MyAppSession_";
});
builder.Services.AddSession(); // Automatically uses the registered Redis cache!

5. Interview Mastery

Q: "If you store sensitive user preferences, would you use Session or Cookies?"

Architect Answer: "If the data is genuinely sensitive (like an authentication token, financial context, or PII), I strictly use Session State backed by Redis. Cookies live as plain text files on the client's physical hardware, vulnerable to cross-site scripting (XSS), physical machine compromise, or network sniffing if TLS drops. If I must store identifiers in cookies, they are encrypted, digitally signed by ASP.NET Core Data Protection, and marked strictly with HttpOnly and Secure flags to prevent JavaScript access."

Questions on this lesson 0

Sign in to ask a question or upvote helpful answers.

No questions yet — be the first to ask!

ASP.NET Core MVC Mastery
Course syllabus
1. Core Framework
MODULE 1: INTRODUCTION & ENVIRONMENT SETUP
2. View Engine
MODULE 2: .NET CORE FUNDAMENTALS
MODULE 3: ASP.NET CORE BASICS
MODULE 4: MVC FUNDAMENTALS
MODULE 5: DATA PASSING TECHNIQUES
MODULE 6: ROUTING
MODULE 7: VIEWS & UI
MODULE 8: ACTION RESULTS
MODULE 9: HTML HELPERS
MODULE 10: TAG HELPERS
MODULE 11: MODEL BINDING
MODULE 12: VALIDATION
MODULE 13: STATE MANAGEMENT
MODULE 14: FILTERS & SECURITY
MODULE 15: ENTITY FRAMEWORK CORE (DEEP DIVE)
MODULE 16: DESIGN PATTERNS
MODULE 17: FILE HANDLING
MODULE 18: ADVANCED ASP.NET CORE
MODULE 19: PERFORMANCE & BEST PRACTICES
MODULE 20: RAZOR PAGES (BONUS)
MODULE 21: REAL-WORLD PROJECTS (🔥 MUST DO)
Toolliyo Assistant
Ask about tutorials, ebooks, training, pricing, mentor services, and support. I use public site content only—not admin or internal tools.

care@toolliyo.com

Need callback? Share your details