Skip to content

Conversation

@dariatiurina
Copy link
Contributor

@dariatiurina dariatiurina commented Dec 12, 2025

TempData support for Blazor

Summary

Right now Blazor does not support TempData or similar systems, like there is support for such in MVC. This PR fixes this gap and gives users native support for persisting data between requests in Blazor SSR.

Changes

Summary of changes:

  • Added a new ITempData interface defining methods for storing, retrieving, peeking, and retaining temporary data, as well as indexer access.
  • Implemented the TempData class, providing the logic for managing temporary data, including methods for getting, peeking, keeping, saving, and loading data.
  • Integrated TempData into the service collection, making it available as a cascading value in Blazor endpoint scenarios. It loads TempData from the HttpContext and ensures it is saved back to cookies on response.
  • Added TempDataService for serializing/deserializing TempData to/from cookies, handling supported types and data conversion.
  • Added end-to-end and unit tests verifying that TempData and TempDataService work correctly and as intended.

Public API

ITempData

ITempData is an interface for the custom IDictionary. This is our base for the TempData implementation.

namespace Microsoft.AspNetCore.Components;

public interface ITempData : IDictionary<string, object?>
{
    object? Get(string key);
    object? Peek(string key);
    void Keep();
    void Keep(string key);
}

TempData

This is a concrete implementation for the TempData. The crucial part here are methods Save and Load that are responsible for saving TempData to Cookie and loading data from Cookie respectively.

public class TempData : ITempData
{
    public TempData();
    public object? this[string key] { get; set; }
    public object? Get(string key);
    public object? Peek(string key);
    public void Keep();
    public void Keep(string key);
    public bool ContainsKey(string key);
    public bool Remove(string key);
    public bool ContainsValue(object? value);
    public void Clear();
    public IDictionary<string, object?> Save();
    public void Load(IDictionary<string, object?> data);
}

Tests

Unit tests in src/Components/Components/test/TempDataTest.cs:

  • Indexer can set and get values
  • Get returns value and removes from retained keys
  • Peek returns value without removing from retained keys
  • Keep() retains all keys for another request
  • Keep(string) retains specific key for another request
  • ContainsKey returns correct results
  • Remove removes key and returns success
  • Save returns only retained keys
  • Load populates data from dictionary
  • Clear removes all data
  • Keys are case-insensitive

Unit tests in src/Components/Endpoints/test/TempDataServiceTest.cs:

  • Load returns empty TempData when no cookie exists
  • Save deletes cookie when no data to save
  • Save sets cookie when data exists
  • RoundTrip preserves string, int, bool, Guid, DateTime values
  • RoundTrip preserves string arrays and int arrays
  • RoundTrip preserves Dictionary<string, string>
  • Save throws for unsupported types
  • Load returns empty TempData for invalid/corrupted cookies

E2E tests in src/Components/test/E2ETest/Tests/TempDataTest.cs:

  • Values persist after same-page redirect
  • Values persist across different pages
  • Peek preserves values for subsequent requests
  • Keep() retains all values
  • Keep(key) retains specific value
  • Remove() deletes values
  • ContainsKey works correctly

API usage

Basic form with flash messages:

@page "/my-form"
@inject NavigationManager NavigationManager

<p id="message">@_message</p>

<form method="post" @formname="MyForm" @onsubmit="HandleSubmit">
    <AntiforgeryToken />
    <input type="text" name="Name" />
    <button type="submit">Submit</button>
</form>

@code {
    [CascadingParameter]
    public ITempData? TempData { get; set; }

    private string? _message;

    protected override void OnInitialized()
    {
        // Get removes the value after reading (one-time use)
        _message = TempData?.Get("Message") as string ?? "No message";
    }

    private void HandleSubmit()
    {
        // Set success message
        TempData!["Message"] = "Form submitted successfully!";
        
        // Redirect - message will be available on next request
        NavigationManager.NavigateTo("/my-form", forceLoad: true);
    }
}

Reading without consuming (Peek):

@code {
    protected override void OnInitialized()
    {
        // Peek reads without removing - value available on next request too
        var notification = TempData?.Peek("Notification") as string;
    }
}

Keeping values for another request:

@code {
    protected override void OnInitialized()
    {
        var message = TempData?.Get("Message") as string;
        
        // Keep this specific value for one more request
        TempData?.Keep("Message");
        
        // Or keep all values
        TempData?.Keep();
    }
}

Fixes #49683

@github-actions github-actions bot added the area-blazor Includes: Blazor, Razor Components label Dec 12, 2025
@dariatiurina dariatiurina self-assigned this Dec 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-blazor Includes: Blazor, Razor Components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Blazor TempData

1 participant