Skip to content

SupplyParameterFromSession support for Blazor#65184

Open
dariatiurina wants to merge 11 commits intodotnet:mainfrom
dariatiurina:64422-session-data
Open

SupplyParameterFromSession support for Blazor#65184
dariatiurina wants to merge 11 commits intodotnet:mainfrom
dariatiurina:64422-session-data

Conversation

@dariatiurina
Copy link
Contributor

@dariatiurina dariatiurina commented Jan 22, 2026

SupplyParameterFromSession support for Blazor

Summary

Enable Blazor SSR developers to easily read and write session data using a declarative [SupplyParameterFromSession] attribute, providing a familiar pattern consistent with existing [SupplyParameterFromQuery] and [SupplyParameterFromForm] attributes.

Motivation

Currently, Blazor SSR lacks a simple, declarative way to access session data. Developers who want to persist user-specific data across HTTP requests (like shopping cart contents or multi-step form state) must:

  • Inject IHttpContextAccessor and manually interact with ISession
  • Handle serialization/deserialization manually
  • Write boilerplate code for each session value

This creates inconsistent patterns across applications and increases the likelihood of errors. MVC Razor Pages developers have easier access to session data, and Blazor SSR should offer a similar experience.

Goals

  • Enable developers to read session data declaratively using [SupplyParameterFromSession]
  • Enable developers to write session data by simply assigning values to decorated properties
  • Provide automatic JSON serialization/deserialization for supported types
  • Support custom session key names via the Name property
  • Make session keys case-insensitive for consistency
  • Integrate seamlessly with existing AddRazorComponents() setup

Non-Goals

  • Not replacing Session or databases for long-term storage
  • Not providing manipulation beyond read/write through the attribute
  • Not supporting all possible types - focus on JSON-serializable types
  • Not providing session management features (expiration, cleanup, etc.)
  • Not supporting WebAssembly or Server interactivity modes (SSR only in Phase 1)

Scenarios

Scenario 1: Multi-step form wizard

As a developer, I want to preserve form data across multiple pages so that users don't lose their input when navigating between steps.

  • Context: Building a checkout flow with shipping, payment, and confirmation pages
  • Flow: User fills Page 1 → Data persists to session → User navigates to Page 2 → Previous data available
  • Cleanup: Session data persists until session expires or is explicitly cleared

Scenario 2: User preferences

As a developer, I want to store user preferences (like theme or language) in the session so that they persist across page navigations without requiring database storage.

  • Context: Storing temporary user choices that don't need permanent storage
  • Flow: User selects preference → Stored in session → Available on all subsequent requests

Scenario 3: Shopping cart (before checkout)

As a developer, I want to maintain a shopping cart across pages so users can continue browsing and adding items.

  • Context: E-commerce application with anonymous shopping
  • Flow: User adds item → Cart stored in session → User navigates → Cart preserved

Detailed Design

Core Components

1. SupplyParameterFromSessionAttribute

A new attribute that inherits from CascadingParameterAttributeBase:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class SupplyParameterFromSessionAttribute : CascadingParameterAttributeBase
{
    /// <summary>
    /// Gets or sets the name of the session key. If not specified, the property name will be used.
    /// </summary>
    public string? Name { get; set; }
}

2. ISessionValueMapper Interface

public interface ISessionValueMapper
{
    object? GetValue(string sessionKey, Type targetType);
    void RegisterValueCallback(string sessionKey, Func<object?> valueGetter);
}

3. SessionValueMapper Implementation

The SessionValueMapper class handles:

  • Reading values from session and deserializing via System.Text.Json
  • Registering callbacks to persist values when the response starts
  • Converting session keys to lowercase for case-insensitivity

Lifecycle Flow

Component Rendered 
    ↓
Subscribe (RegisterValueCallback) 
    ↓
GetValue (read from session)
    ↓
Property available for use
    ↓
Response.OnStarting → PersistAllValues
    ↓
Values serialized to session

We do not use Unsubcribe due to complicated situations with the disposal of the components in SSR.

Usage Examples

Basic usage - reading and writing:

@page "/profile"

<input @bind="Email" />

@code {
    [SupplyParameterFromSession]
    public string? Email { get; set; }
    
    void UpdateEmail()
    {
        // Simply assign - value persists to session automatically
        Email = "new@email.com";
    }
}

Custom session key name:

[SupplyParameterFromSession(Name = "user_email")]
public string? UserEmail { get; set; }

Complex types:

[SupplyParameterFromSession]
public ShoppingCart? Cart { get; set; }

public class ShoppingCart
{
    public List<CartItem> Items { get; set; } = new();
    public decimal Total { get; set; }
}

Multi-step form:

// Page1.razor
[SupplyParameterFromSession]
public FormData? WizardData { get; set; }

void Next()
{
    WizardData = new FormData { Step1Value = inputValue };
    NavigationManager.NavigateTo("/page2", forceLoad: true);
}

// Page2.razor - WizardData is automatically available

Supported Types

  • Primitives: string, int, bool, double, decimal, etc.
  • Common types: Guid, DateTime, DateTimeOffset
  • Nullable versions: int?, DateTime?, etc.
  • Collections: List<T>, Dictionary<string, T>, arrays
  • Enums: All enum types
  • Custom classes: Any JSON-serializable class

Registration

The feature is automatically enabled when using AddRazorComponents():

// In RazorComponentsServiceCollectionExtensions
services.TryAddScoped<ISessionValueMapper, SessionValueMapper>();
services.AddSupplyValueFromSessionProvider();

Developers must still configure session middleware in their application:

// Program.cs
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession(options =>
{
    options.Cookie.HttpOnly = true;
    options.Cookie.IsEssential = true;
});

// ...

app.UseSession();

Risks and Unknowns

Risk 1: Session size limits

Developers may store excessive data in session, impacting performance.

Risk 2: Serialization failures

Complex types may fail to serialize/deserialize.

Risk 3: Session not configured

Developers may forget to configure session middleware.

Unknown: Performance impact

Need to measure the overhead of JSON serialization/deserialization per request.

Drawbacks

  • Requires session middleware to be configured separately
  • Only works with Blazor SSR (not WebAssembly or Server interactivity)
  • JSON serialization adds overhead compared to raw session access
  • Values persist only until session expires - not suitable for long-term storage
  • Developers must understand session lifecycle

Considered Alternatives

Alternative 1: TempData approach

Reuse MVC's TempData infrastructure.

Why rejected: TempData has single-read semantics (values are removed after reading), which doesn't fit session persistence use cases.

Alternative 2: ProtectedSessionStorage

Use the existing ProtectedSessionStorage from Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage.

Why rejected: Requires JavaScript interop, which is incompatible with Blazor SSR's static rendering model.

Alternative 3: Direct ISession injection

Developers inject IHttpContextAccessor and use ISession directly.

Why rejected: Works but is verbose and inconsistent with other SupplyParameterFrom* patterns. This proposal provides a better developer experience while still using ISession under the hood.

Examples

Complete multi-page form example

Step1.razor:

@page "/wizard/step1"

<form @onsubmit="GoToStep2" @formname="step1" method="post">
    <AntiforgeryToken />
    <input @bind="FormInput" name="FormInput" />
    <button type="submit">Next</button>
</form>

@code {
    [SupplyParameterFromSession]
    public WizardState? State { get; set; }
    
    [SupplyParameterFromForm]
    public string? FormInput { get; set; }
    
    void GoToStep2()
    {
        State = new WizardState { Name = FormInput };
        NavigationManager.NavigateTo("/wizard/step2", forceLoad: true);
    }
}

Step2.razor:

@page "/wizard/step2"

<p>Hello, @State?.Name!</p>
<input @bind="EmailInput" />
<button @onclick="Complete">Complete</button>

@code {
    [SupplyParameterFromSession]
    public WizardState? State { get; set; }
    
    string? EmailInput { get; set; }
    
    void Complete()
    {
        State!.Email = EmailInput;
        NavigationManager.NavigateTo("/wizard/complete", forceLoad: true);
    }
}

Open Questions

  1. Should we provide a way to clear session values explicitly through the attribute?
  2. What's the performance impact of JSON serialization on high-traffic pages?
  3. Should we add support for custom serializers?

Fixes #64422

@github-actions github-actions bot added the area-blazor Includes: Blazor, Razor Components label Jan 22, 2026
@dariatiurina dariatiurina self-assigned this Feb 2, 2026
@dariatiurina dariatiurina marked this pull request as ready for review February 3, 2026 14:01
@dariatiurina dariatiurina requested a review from a team as a code owner February 3, 2026 14:01
Copilot AI review requested due to automatic review settings February 9, 2026 16:58
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds [SupplyParameterFromSession] support for Blazor SSR by introducing a session-backed cascading value supplier and request-scoped session value mapper, plus test assets and E2E/unit tests to validate behavior.

Changes:

  • Introduces SupplyParameterFromSessionAttribute, session value provider, and ISessionValueMapper/SessionValueMapper.
  • Wires session value mapper into EndpointHtmlRenderer request initialization and registers services via AddRazorComponents().
  • Adds test server pages and E2E/unit tests for reading/writing session-backed parameters across navigations.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/SupplyParameterFromSessionNavigationComponent.razor Adds navigation test page used to validate session persistence across redirects.
src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/SupplyParameterFromSessionComponent.razor Adds SSR test page exercising primitive, named-key, null, and complex session values.
src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsNoInteractivityStartup.cs Adds conditional session service/middleware setup for the tests.
src/Components/test/testassets/Components.TestServer/Components.TestServer.csproj Adds Session assembly reference for the test server.
src/Components/test/E2ETest/Tests/SupplyParameterFromSessionAttributeTest.cs Adds E2E coverage for session parameter read/write and navigation persistence.
src/Components/Endpoints/test/SessionValueMapperTest.cs Adds unit tests for SessionValueMapper serialization, persistence, and error handling.
src/Components/Endpoints/src/Session/SupplyParameterFromSessionValueProvider.cs Implements the cascading value supplier that binds component properties to session keys.
src/Components/Endpoints/src/Session/SupplyParameterFromSessionServiceCollectionExtensions.cs Adds DI extension to register the session value supplier.
src/Components/Endpoints/src/Session/SessionValueMapper.cs Implements session read/write with JSON serialization and response on-start persistence.
src/Components/Endpoints/src/Session/ISessionValueMapper.cs Adds public contract for session value mapping and persistence callbacks.
src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs Initializes the session mapper with the current request HttpContext.
src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.Prerendering.cs Widens accessibility of overrides (likely to enable cross-assembly usage).
src/Components/Endpoints/src/Rendering/EndpointComponentState.cs Widens accessibility of GetComponentKey override.
src/Components/Endpoints/src/PublicAPI.Unshipped.txt Declares newly added public APIs for the Endpoints assembly.
src/Components/Endpoints/src/DependencyInjection/RazorComponentsServiceCollectionExtensions.cs Registers ISessionValueMapper and session value provider in AddRazorComponents().
src/Components/Components/src/SupplyParameterFromSessionAttribute.cs Adds the public attribute for supplying values from session.
src/Components/Components/src/PublicAPI.Unshipped.txt Declares newly added public APIs for the Components assembly.
src/Components/Components/src/Microsoft.AspNetCore.Components.csproj Adds internals visibility to allow Endpoints to consume internal attribute members.

@dotnet-policy-service
Copy link
Contributor

Looks like this PR hasn't been active for some time and the codebase could have been changed in the meantime.
To make sure no conflicting changes have occurred, please rerun validation before merging. You can do this by leaving an /azp run comment here (requires commit rights), or by simply closing and reopening.

@dotnet-policy-service dotnet-policy-service bot added the pending-ci-rerun When assigned to a PR indicates that the CI checks should be rerun label Feb 23, 2026
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 pending-ci-rerun When assigned to a PR indicates that the CI checks should be rerun

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Blazor SessionData

2 participants