Fix TempData and SupplyParameterFromSession persistence for streaming SSR case#66832
Open
dariatiurina wants to merge 1 commit into
Open
Fix TempData and SupplyParameterFromSession persistence for streaming SSR case#66832dariatiurina wants to merge 1 commit into
dariatiurina wants to merge 1 commit into
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes persistence timing for [SupplyParameterFromSession] and TempData during streaming server-side rendering (SSR) by moving persistence from HttpResponse.OnStarting callbacks to explicit persistence calls made after rendering/streaming completes.
Changes:
- Added explicit post-render persistence calls for session-supplied cascading values and TempData in
RazorComponentEndpointInvoker. - Removed
Response.OnStarting-based persistence registration fromSessionCascadingValueSupplierand TempData creation. - Updated session-related unit tests to call
PersistAllValues()explicitly.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Components/Endpoints/src/RazorComponentEndpointInvoker.cs | Adds explicit session + TempData persistence after rendering/streaming completes. |
| src/Components/Endpoints/src/SessionCascadingValueSupplier.cs | Removes OnStarting registration so persistence is driven externally. |
| src/Components/Endpoints/src/TempData/TempDataProviderServiceCollectionExtensions.cs | Removes OnStarting persistence and adds PersistTempData(HttpContext) helper. |
| src/Components/Endpoints/test/Session/SessionSubscriptionTest.cs | Updates subscription test to use explicit persistence instead of firing OnStarting. |
| src/Components/Endpoints/test/Session/SessionCascadingValueSupplierTest.cs | Renames/updates test to validate explicit persistence behavior. |
Comment on lines
+176
to
+183
| // Persist TempData and Session values after all components (including streaming) | ||
| // have finished rendering, so that values modified during async rendering are captured. | ||
| if (context.RequestServices.GetService<SessionCascadingValueSupplier>() is { } sessionSupplier) | ||
| { | ||
| await sessionSupplier.PersistAllValues(); | ||
| } | ||
| TempDataProviderServiceCollectionExtensions.PersistTempData(context); | ||
|
|
| internal static void PersistTempData(HttpContext httpContext) | ||
| { | ||
| if (httpContext.Items.TryGetValue(HttpContextItemKey, out var tempDataObj) && tempDataObj is TempData tempData) | ||
| { |
| { | ||
| _supplier.RegisterValueCallback("key", () => "value"); | ||
|
|
||
| var httpContext = CreateHttpContextWithSession(out var responseFeature); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fix TempData and SupplyParameterFromSession persistence for streaming SSR case
Description
Fixes a bug where
[SupplyParameterFromSession]and session-basedTempDatavalues were not persisted correctly during streaming SSR. Both mechanisms previously relied onResponse.OnStartingcallbacks to save their state, which fires right before the response begins — meaning any values modified during async/streaming rendering were lost.This PR replaces the
OnStarting-based persistence with explicit calls inRazorComponentEndpointInvoker, placed after all rendering (including streaming) completes.Changes
RazorComponentEndpointInvoker.cs: Added explicit calls toSessionCascadingValueSupplier.PersistAllValues()andTempDataProviderServiceCollectionExtensions.PersistTempData()after rendering completes (afterSendStreamingUpdatesAsync/EmitInitializersIfNecessary), but before persisted component state is emitted and beforeBufferedTextWriter.FlushAsync().SessionCascadingValueSupplier.cs: Removed the_onStartingRegisteredfield and theResponse.OnStarting(PersistAllValues)callback registration fromCreateSubscription. Persistence is now triggered externally by the endpoint invoker.TempDataProviderServiceCollectionExtensions.cs: Removed theResponse.OnStartingcallback fromGetOrCreateTempData. Added a newPersistTempData(HttpContext)static method that saves TempData on demand, called by the endpoint invoker at the right time.Tests updated:
SessionCascadingValueSupplierTestandSessionSubscriptionTestupdated to reflect the new explicit persistence model — tests now callPersistAllValues()directly instead ofFireOnStartingAsync().How persistence timing works
The key to understanding this change is the
BufferedTextWriterused byRenderComponentCore. This writer accumulates all HTML output in memory and only flushes toResponse.Body(starting the HTTP response) whenFlushAsync()is explicitly called at the very end of the method.Non-streaming case
In the non-streaming path, the persistence calls and the old
OnStartingapproach are functionally equivalent — both execute beforeResponse.HasStarted:Cookie-based
TempDataworks here becauseSet-Cookieheaders can still be added before the flush.Streaming case
In the streaming path,
SendStreamingUpdatesAsyncflushes the buffer internally, starting the response mid-render. The explicit persistence calls happen after streaming completes:This is why the fix matters for streaming:
OnStarting): Fired before the response started, so it ran before streaming components finished — values modified during streaming were silently lost.Cookie-based
TempDatacannot work in the streaming case regardless of approach — HTTP headers (Set-Cookie) cannot be set after the response body has started. This is not a regression; cookies are fundamentally incompatible with streaming SSR. Session-based persistence ([SupplyParameterFromSession]and session-basedTempData) works correctly because session state is stored server-side and doesn't depend on response headers.Testing
Existing unit tests updated:
SessionCascadingValueSupplierTest.SetRequestContext_DoesNotPersist_UntilExplicitlyCalled— verifies values aren't persisted untilPersistAllValues()is explicitly invokedSessionSubscriptionTest.CreateSubscription_RegistersValueCallbackAndReturnsSubscription— updated to usePersistAllValues()instead ofFireOnStartingAsync()Fixes #66745