DEV Community

nikosst
nikosst

Posted on

ASP.NET Core Deep Dive: ViewData vs ViewBag vs TempData vs Session

As ASP.NET Core developers, we often need to transfer data between controllers, views, requests, and even user sessions. The framework provides several mechanisms for this purpose: ViewData, ViewBag, TempData, and Session.

Many junior developers learn these concepts separately and end up using them interchangeably. In reality, each one solves a completely different problem, has a different lifecycle, and affects maintainability in different ways.

Understanding when to use each mechanism is essential for building scalable and maintainable MVC applications.


Why So Many Options Exist?

Imagine an e-commerce application.

Sometimes you need to pass data from a controller to a view.

Sometimes you need data to survive a redirect.

Sometimes you need information available across multiple requests.

Sometimes you need user-specific state that remains available during an entire browsing session.

These are fundamentally different requirements. Microsoft introduced different mechanisms because a single solution would either be inefficient or overly complex.

The key distinction is scope and lifetime.


ViewData

ViewData is the oldest mechanism inherited from classic ASP.NET MVC.

Internally, it is a dictionary of type:

ViewDataDictionary
Enter fullscreen mode Exit fullscreen mode

which stores data as key-value pairs.

A controller can populate the dictionary and the view can read from it.

public IActionResult Details()
{
    ViewData["Title"] = "Product Details";
    ViewData["ProductCount"] = 15;

    return View();
}
Enter fullscreen mode Exit fullscreen mode

Inside the Razor view:

<h1>@ViewData["Title"]</h1>

<p>Total Products: @ViewData["ProductCount"]</p>
Enter fullscreen mode Exit fullscreen mode

Although simple, ViewData has a major weakness.

Because everything is stored as object, type casting becomes necessary.

int count = (int)ViewData["ProductCount"];
Enter fullscreen mode Exit fullscreen mode

This means compile-time safety is lost.

If someone changes the type later, the application may fail at runtime.

For this reason, ViewData is generally considered suitable only for small pieces of UI-related information.

Examples include:

Page titles
Breadcrumb text
Display messages
Minor metadata

Using ViewData for complex business objects usually creates maintenance problems.


ViewBag

ViewBag was introduced to make ViewData easier to use.

Interestingly, ViewBag is not a separate storage mechanism.

Internally it wraps ViewData using dynamic properties.

When you write:

ViewBag.Title = "Product Details";
Enter fullscreen mode Exit fullscreen mode

ASP.NET Core actually stores the value inside ViewData.

The equivalent ViewData version is:

ViewData["Title"] = "Product Details";
Enter fullscreen mode Exit fullscreen mode

The controller:

public IActionResult Details()
{
    ViewBag.ProductName = "Gaming Laptop";
    ViewBag.Price = 1500;

    return View();
}
Enter fullscreen mode Exit fullscreen mode

The view:

<h2>@ViewBag.ProductName</h2>

<p>Price: @ViewBag.Price €</p>
Enter fullscreen mode Exit fullscreen mode

The syntax is cleaner and easier to read.

However, ViewBag introduces another problem: the use of dynamic.

Consider:

ViewBag.ProductName
Enter fullscreen mode Exit fullscreen mode

the compiler will not detect the typo.

The error appears only during execution.

For small MVC applications this may not matter, but in enterprise systems it becomes a source of bugs.

That is why many senior developers prefer strongly typed ViewModels over both ViewData and ViewBag.


ViewData vs ViewBag

Since both use the same underlying storage, their lifecycle is identical.

They exist only during the current request.

Once the response is sent, the data disappears.

The following diagram describes their lifecycle conceptually:

Controller → View → Destroyed

Neither survives redirects.

Consider:

public IActionResult Save()
{
    ViewBag.Message = "Saved";

    return RedirectToAction("Index");
}
Enter fullscreen mode Exit fullscreen mode

The message will be lost.

The redirect creates an entirely new HTTP request.

This is where TempData enters the picture.


TempData

TempData was designed specifically for passing data between requests.

Most commonly, it is used after redirects.

A typical scenario is the Post-Redirect-Get pattern.

[HttpPost]
public IActionResult Save(Product product)
{
    // Save logic

    TempData["Success"] = "Product saved successfully";

    return RedirectToAction("Index");
}
Enter fullscreen mode Exit fullscreen mode

Then:

public IActionResult Index()
{
    return View();
}
Enter fullscreen mode Exit fullscreen mode

Inside the view:

@if (TempData["Success"] != null)
{
    <div class="alert alert-success">
        @TempData["Success"]
    </div>
}
Enter fullscreen mode Exit fullscreen mode

The user sees the message after the redirect.

This would not be possible using ViewData or ViewBag.


The Special Behavior of TempData

TempData behaves differently from the other mechanisms.

By default, data is automatically removed after it is read.

For example:

var message = TempData["Success"];
Enter fullscreen mode Exit fullscreen mode

After this line executes, the value is marked for deletion.

If you need to preserve it:

TempData.Keep();
Enter fullscreen mode Exit fullscreen mode

Or:

TempData.Keep("Success");
Enter fullscreen mode Exit fullscreen mode

You can also inspect a value without removing it:

var message = TempData.Peek("Success");
Enter fullscreen mode Exit fullscreen mode

This makes TempData ideal for:

Success notifications
Error messages
Wizard workflows
Redirect scenarios

It is not suitable for long-term storage.


Session

Session solves a completely different problem.

While ViewData, ViewBag, and TempData focus on controller/view communication, Session stores user-specific state across many requests.

Imagine a shopping cart.

A user may browse dozens of pages before checking out.

The cart must remain available throughout the session.

HttpContext.Session.SetString(
    "Username",
    "Nick"
);
Enter fullscreen mode Exit fullscreen mode

Reading:

var username =
    HttpContext.Session.GetString(
        "Username"
    );
Enter fullscreen mode Exit fullscreen mode

Unlike ViewData and TempData, Session can remain available for minutes or hours depending on configuration.


Configuring Session in ASP.NET Core

First, register Session services:

builder.Services.AddDistributedMemoryCache();

builder.Services.AddSession(options =>
{
    options.IdleTimeout =
        TimeSpan.FromMinutes(30);
});
Enter fullscreen mode Exit fullscreen mode

Then enable middleware:

app.UseSession();
Enter fullscreen mode Exit fullscreen mode

Now Session becomes available through:

HttpContext.Session
Enter fullscreen mode Exit fullscreen mode

Without this configuration, Session operations will fail.


Session and Complex Objects

Session natively supports strings and byte arrays.

For custom objects, serialization is required.

Example:

public class ShoppingCart
{
    public int ItemCount { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

Store:

var cart = new ShoppingCart
{
    ItemCount = 5
};

HttpContext.Session.SetString(
    "Cart",
    JsonSerializer.Serialize(cart)
);
Enter fullscreen mode Exit fullscreen mode

Retrieve:

var json =
    HttpContext.Session.GetString(
        "Cart"
    );

var cart =
    JsonSerializer.Deserialize<ShoppingCart>(
        json
    );
Enter fullscreen mode Exit fullscreen mode

This approach is common in real-world applications.


Performance Considerations

A frequent mistake is treating Session as a database.

Session should store only small amounts of user-specific state.

Storing large datasets increases memory consumption and hurts scalability.

In distributed environments, Session data often ends up in:

  • Redis
  • SQL Server
  • Distributed Cache Providers

The larger the Session, the slower the application becomes.

A good rule is simple:

If data belongs in a database, keep it in a database.


What Senior Developers Usually Choose

In modern ASP.NET Core applications, strongly typed ViewModels are generally preferred over ViewData and ViewBag.

Example:

public class ProductViewModel
{
    public string Name { get; set; }

    public decimal Price { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

Controller:

public IActionResult Details()
{
    var model =
        new ProductViewModel
        {
            Name = "Laptop",
            Price = 1500
        };

    return View(model);
}
Enter fullscreen mode Exit fullscreen mode

View:

@model ProductViewModel

<h2>@Model.Name</h2>

<p>@Model.Price €</p>
Enter fullscreen mode Exit fullscreen mode

This provides:

  • Compile-time checking
  • IntelliSense support
  • Easier refactoring
  • Better maintainability

Consequently, ViewData and ViewBag are often reserved for small UI metadata.


Modern ASP.NET Core Perspective

While ViewData, ViewBag, TempData, and Session remain fully supported in ASP.NET Core, their role has evolved. Modern applications favor strongly typed ViewModels, DTOs, and API-based architectures because they provide better maintainability, testability, and compile-time safety. ViewData and ViewBag are now typically reserved for small UI-related values, TempData remains a practical solution for passing messages across redirects, and Session is used more selectively for user-specific state. The key takeaway is that these mechanisms are still valuable, but in contemporary ASP.NET Core development they are no longer the primary way application data is modeled and transferred.


Final Verdict

The biggest mistake developers make is viewing these four mechanisms as alternatives. They are not.

ViewData and ViewBag exist to pass data from a controller to a view during a single request.

TempData exists to transfer data between requests, especially after redirects.

Session exists to maintain user-specific state across multiple requests and pages.

When selecting one, ask a single question:

How long should the data live?

If the answer is until the view renders, use ViewData, ViewBag, or preferably a ViewModel.

If the answer is until the next request, use TempData.

If the answer is throughout the user's interaction with the application, use Session.

Understanding this distinction is one of those small architectural decisions that separates maintainable ASP.NET Core applications from those that become increasingly difficult to evolve over time.


Συμπεράσματα

Ένα από τα μεγαλύτερα λάθη που κάνουν οι προγραμματιστές είναι να αντιμετωπίζουν τα ViewData, ViewBag, TempData και Session ως εναλλακτικές λύσεις για το ίδιο πρόβλημα. Στην πραγματικότητα, δεν είναι.

Το ViewData και το ViewBag υπάρχουν για να μεταφέρουν δεδομένα από έναν Controller σε ένα View κατά τη διάρκεια του ίδιου HTTP request.

Το TempData σχεδιάστηκε για τη μεταφορά δεδομένων μεταξύ διαδοχικών requests, κυρίως σε σενάρια όπου μεσολαβεί κάποιο redirect.

Το Session εξυπηρετεί έναν εντελώς διαφορετικό σκοπό: τη διατήρηση δεδομένων που αφορούν τον συγκεκριμένο χρήστη σε πολλαπλά requests και σε διαφορετικές σελίδες της εφαρμογής.

Όταν έρχεται η στιγμή να επιλέξετε ποιον μηχανισμό θα χρησιμοποιήσετε, κάντε πρώτα μία απλή ερώτηση:

«Για πόσο χρονικό διάστημα πρέπει να παραμείνουν διαθέσιμα αυτά τα δεδομένα;»

Αν τα δεδομένα χρειάζονται μόνο μέχρι να γίνει η απόδοση του View, τότε το ViewData, το ViewBag ή ακόμη καλύτερα ένα ισχυρά τυποποιημένο ViewModel αποτελούν τις κατάλληλες επιλογές.

Αν τα δεδομένα πρέπει να επιβιώσουν μέχρι το επόμενο request, τότε το TempData είναι η σωστή λύση.

Αν τα δεδομένα πρέπει να παραμείνουν διαθέσιμα καθ' όλη τη διάρκεια της αλληλεπίδρασης του χρήστη με την εφαρμογή, τότε το Session είναι ο κατάλληλος μηχανισμός.

Η κατανόηση αυτής της διαφοράς μπορεί να φαίνεται ως μια μικρή αρχιτεκτονική λεπτομέρεια. Στην πράξη, όμως, είναι μία από εκείνες τις αποφάσεις που διαχωρίζουν τις καθαρές, επεκτάσιμες και εύκολα συντηρήσιμες εφαρμογές ASP.NET Core από εκείνες που με την πάροδο του χρόνου γίνονται ολοένα και πιο δύσκολες στη συντήρηση και την εξέλιξή τους.


nikosstit@gmail.com

Top comments (0)