Skip to content

Commit e0d817e

Browse files
committed
tmp
1 parent 2c11600 commit e0d817e

File tree

8 files changed

+307
-70
lines changed

8 files changed

+307
-70
lines changed

AspNetCore.slnx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,6 +1143,7 @@
11431143
<Project Path="src/SignalR/server/StackExchangeRedis/src/Microsoft.AspNetCore.SignalR.StackExchangeRedis.csproj" />
11441144
<Project Path="src/SignalR/server/StackExchangeRedis/test/Microsoft.AspNetCore.SignalR.StackExchangeRedis.Tests.csproj" />
11451145
</Folder>
1146+
<Folder Name="/src/SiteExtensions/" />
11461147
<Folder Name="/src/SiteExtensions/Microsoft.Web.Xdt.Extensions/">
11471148
<Project Path="src/SiteExtensions/Microsoft.Web.Xdt.Extensions/src/Microsoft.Web.Xdt.Extensions.csproj" />
11481149
<Project Path="src/SiteExtensions/Microsoft.Web.Xdt.Extensions/tests/Microsoft.Web.Xdt.Extensions.Tests.csproj" />

Review.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
###
2+
3+
src/Components/Components/src/PersistentComponentState.cs
4+
5+
public RestoringComponentStateSubscription RegisterOnRestoring(IPersistentStateFilter? filter, Action callback)
6+
7+
Reorder parameters, action first, filter later.
8+
9+
Pass in multiple filters? (and create a composite filter)
10+
11+
params Span<IPersistentComponentStateFilter>
12+
13+
###
14+
15+
src/Components/Components/src/PersistentState/ComponentStatePersistenceManager.cs
16+
17+
public async Task RestoreStateAsync(IPersistentComponentStateStore store, IPersistentComponentStateScenario? scenario)
18+
19+
Make scenario required (can't pass null)
20+
21+
Remove extra line at the end. (307)
22+
23+
###
24+
25+
src/Components/Components/src/PersistentState/RestoreStateOnPrerenderingAttribute.cs
26+
src/Components/Components/src/PersistentState/RestoreStateOnReconnectionAttribute.cs
27+
src/Components/Components/src/PersistentState/UpdateStateOnEnhancedNavigation.cs
28+
src/Components/Components/src/PersistentState/WebPersistenceFilter.cs
29+
src/Components/Components/src/PersistentState/WebPersistenceScenario.cs
30+
31+
Move these types to src/Components/Web/src/Restore/.
32+
33+
###
34+
35+
src/Components/Components/src/PersistentStateValueProvider.cs
36+
37+
Move CompositeScenarioFilter to its own file.
38+
39+
Move CreateFilter inside ComponentSubscription
40+
41+
Move the Log class to ComponentSubscription.
42+
43+
Move ComponentSubscription into its own file.
44+
45+
Move ResolvePropertyGetter SerializerFactory and PropertyGetterFactory into ComponentSubscription.
46+
47+
Move _serializerCache, _propertyGetterCache and _keyCache into ComponentSubscription.
48+
49+
Update the `ComponentSubscription` constructor to take in the "source" values and compute the property getter, the custom serializer, and so on inside the constructor.
50+

src/Components/WebAssembly/WebAssembly/src/Rendering/WebAssemblyRenderer.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,12 @@ private void OnUpdateRootComponents(RootComponentOperationBatch batch, string ap
5353
{
5454
var webRootComponentManager = GetOrCreateWebRootComponentManager();
5555

56-
var store = new PrerenderComponentApplicationStore(appState);
57-
_ = _componentStatePersistenceManager.RestoreStateAsync(store, WebPersistenceScenario.EnhancedNavigation);
56+
var store = !string.IsNullOrEmpty(appState) ? new PrerenderComponentApplicationStore(appState) : null;
57+
if (store != null)
58+
{
59+
// Restore the state from the store if it exists
60+
_ = _componentStatePersistenceManager.RestoreStateAsync(store, WebPersistenceScenario.Prerendering);
61+
}
5862

5963
for (var i = 0; i < batch.Operations.Length; i++)
6064
{
@@ -81,7 +85,7 @@ private void OnUpdateRootComponents(RootComponentOperationBatch batch, string ap
8185
}
8286
}
8387

84-
store.ExistingState.Clear();
88+
store?.ExistingState.Clear();
8589

8690
NotifyEndUpdateRootComponents(batch.BatchId);
8791
}

src/Components/test/E2ETest/Tests/StatePersistenceTest.cs

Lines changed: 83 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -107,14 +107,24 @@ public void CanRenderComponentWithPersistedState(bool suppressEnhancedNavigation
107107
}
108108
}
109109

110+
// Validates that we can use persisted state across server, webassembly, and auto modes, with and without
111+
// streaming rendering.
112+
// For streaming rendering, we validate that the state is captured and restored after streaming completes.
113+
// For enhanced navigation we validate that the state is captured at the time components are rendered for
114+
// the first time on the page.
115+
// For auto mode, we validate that the state is captured and restored for both server and wasm runtimes.
116+
// In each case, we validate that the state is available until the initial set of components first render reaches quiescence. Similar to how it works for Server and WebAssembly.
117+
// For server we validate that the state is provided every time a circuit is initialized.
110118
[Theory]
111119
[InlineData(typeof(InteractiveServerRenderMode), (string)null)]
112-
[InlineData(typeof(InteractiveServerRenderMode), "ServerStreaming")]
120+
[InlineData(typeof(InteractiveServerRenderMode), "ServerStreaming", Skip = "Streaming not yet supported")]
113121
[InlineData(typeof(InteractiveWebAssemblyRenderMode), (string)null)]
114-
[InlineData(typeof(InteractiveWebAssemblyRenderMode), "WebAssemblyStreaming")]
122+
[InlineData(typeof(InteractiveWebAssemblyRenderMode), "WebAssemblyStreaming", Skip = "Streaming not yet supported")]
115123
[InlineData(typeof(InteractiveAutoRenderMode), (string)null)]
116-
[InlineData(typeof(InteractiveAutoRenderMode), "AutoStreaming")]
117-
public void ComponentWithUpdateStateOnEnhancedNavigationReceivesStateUpdates(Type renderMode, string streaming)
124+
[InlineData(typeof(InteractiveAutoRenderMode), "AutoStreaming", Skip = "Streaming not yet supported")]
125+
public void CanUpdateComponentsWithPersistedStateAndEnhancedNavUpdates(
126+
Type renderMode,
127+
string streaming)
118128
{
119129
var mode = renderMode switch
120130
{
@@ -124,7 +134,8 @@ public void ComponentWithUpdateStateOnEnhancedNavigationReceivesStateUpdates(Typ
124134
_ => throw new ArgumentException($"Unknown render mode: {renderMode.Name}")
125135
};
126136

127-
// Step 1: Navigate to page without components first to establish initial state
137+
// Navigate to a page without components first to make sure that we exercise rendering components
138+
// with enhanced navigation on.
128139
if (streaming == null)
129140
{
130141
Navigate($"subdir/persistent-state/page-no-components?render-mode={mode}&suppress-autostart");
@@ -133,90 +144,70 @@ public void ComponentWithUpdateStateOnEnhancedNavigationReceivesStateUpdates(Typ
133144
{
134145
Navigate($"subdir/persistent-state/page-no-components?render-mode={mode}&streaming-id={streaming}&suppress-autostart");
135146
}
136-
137147
if (mode == "auto")
138148
{
139149
BlockWebAssemblyResourceLoad();
140150
}
141-
142151
Browser.Click(By.Id("call-blazor-start"));
143-
Browser.Click(By.Id("page-with-components-link"));
144-
145-
// Step 2: Validate initial state - no enhanced nav state should be found
146-
ValidateEnhancedNavState(
147-
mode: mode,
148-
renderMode: renderMode.Name,
149-
interactive: streaming == null,
150-
enhancedNavStateFound: false,
151-
enhancedNavStateValue: "no-enhanced-nav-state",
152-
streamingId: streaming,
153-
streamingCompleted: false);
152+
Browser.Click(By.Id("page-with-components-link-and-declarative-state"));
154153

155-
if (streaming != null)
154+
if (mode != "auto")
156155
{
157-
Browser.Click(By.Id("end-streaming"));
158-
ValidateEnhancedNavState(
159-
mode: mode,
160-
renderMode: renderMode.Name,
161-
interactive: true,
162-
enhancedNavStateFound: false,
163-
enhancedNavStateValue: "no-enhanced-nav-state",
164-
streamingId: streaming,
165-
streamingCompleted: true);
156+
RenderComponentsWithDeclarativePersistentStateAndValidate(mode, renderMode, streaming, stateValue: "other");
166157
}
158+
else
159+
{
160+
// For auto mode, validate that the state is persisted for both runtimes and is able
161+
// to be loaded on server and wasm.
162+
RenderComponentsWithDeclarativePersistentStateAndValidate(mode, renderMode, streaming, interactiveRuntime: "server");
167163

168-
// Step 3: Navigate back to page without components (this persists state)
169-
Browser.Click(By.Id("page-no-components-link"));
164+
UnblockWebAssemblyResourceLoad();
165+
Browser.Navigate().Refresh();
170166

171-
// Step 4: Navigate back to page with components via enhanced navigation
172-
// This should trigger [UpdateStateOnEnhancedNavigation] and update the state
173-
Browser.Click(By.Id("page-with-components-link"));
167+
RenderComponentsWithDeclarativePersistentStateAndValidate(mode, renderMode, streaming, interactiveRuntime: "wasm");
168+
}
169+
}
174170

175-
// Step 5: Validate that enhanced navigation state was updated
176-
ValidateEnhancedNavState(
171+
private void RenderComponentsWithDeclarativePersistentStateAndValidate(
172+
string mode,
173+
Type renderMode,
174+
string streaming,
175+
string interactiveRuntime = null,
176+
string stateValue = "restored")
177+
{
178+
AssertDeclarativePageState(
177179
mode: mode,
178180
renderMode: renderMode.Name,
179181
interactive: streaming == null,
180-
enhancedNavStateFound: true,
181-
enhancedNavStateValue: "enhanced-nav-updated",
182+
stateValue: stateValue,
182183
streamingId: streaming,
183-
streamingCompleted: streaming == null);
184+
streamingCompleted: false,
185+
interactiveRuntime: interactiveRuntime);
184186

185-
if (streaming != null)
187+
if (streaming == null)
186188
{
187-
Browser.Click(By.Id("end-streaming"));
188-
ValidateEnhancedNavState(
189+
Browser.Click(By.Id("enhanced-nav-update"));
190+
AssertDeclarativePageState(
189191
mode: mode,
190192
renderMode: renderMode.Name,
191-
interactive: true,
192-
enhancedNavStateFound: true,
193-
enhancedNavStateValue: "enhanced-nav-updated",
193+
interactive: streaming == null,
194+
stateValue: "updated",
194195
streamingId: streaming,
195-
streamingCompleted: true);
196+
streamingCompleted: false,
197+
interactiveRuntime: interactiveRuntime);
198+
return;
196199
}
197-
}
198200

199-
private void ValidateEnhancedNavState(
200-
string mode,
201-
string renderMode,
202-
bool interactive,
203-
bool enhancedNavStateFound,
204-
string enhancedNavStateValue,
205-
string streamingId = null,
206-
bool streamingCompleted = false)
207-
{
208-
Browser.Equal($"Render mode: {renderMode}", () => Browser.FindElement(By.Id("render-mode")).Text);
209-
Browser.Equal($"Streaming id:{streamingId}", () => Browser.FindElement(By.Id("streaming-id")).Text);
210-
Browser.Equal($"Interactive: {interactive}", () => Browser.FindElement(By.Id("interactive")).Text);
211-
if (streamingId == null || streamingCompleted)
212-
{
213-
Browser.Equal($"Enhanced nav state found:{enhancedNavStateFound}", () => Browser.FindElement(By.Id("enhanced-nav-state-found")).Text);
214-
Browser.Equal($"Enhanced nav state value:{enhancedNavStateValue}", () => Browser.FindElement(By.Id("enhanced-nav-state-value")).Text);
215-
}
216-
else
217-
{
218-
Browser.Equal("Streaming: True", () => Browser.FindElement(By.Id("streaming")).Text);
219-
}
201+
Browser.Click(By.Id("end-streaming"));
202+
203+
AssertDeclarativePageState(
204+
mode: mode,
205+
renderMode: renderMode.Name,
206+
interactive: true,
207+
stateValue: stateValue,
208+
streamingId: streaming,
209+
streamingCompleted: true,
210+
interactiveRuntime: interactiveRuntime);
220211
}
221212

222213
[Theory]
@@ -348,4 +339,29 @@ private void AssertPageState(
348339
Browser.Equal("Streaming: True", () => Browser.FindElement(By.Id("streaming")).Text);
349340
}
350341
}
342+
343+
private void AssertDeclarativePageState(
344+
string mode,
345+
string renderMode,
346+
bool interactive,
347+
string stateValue,
348+
string streamingId = null,
349+
bool streamingCompleted = false,
350+
string interactiveRuntime = null)
351+
{
352+
Browser.Equal($"Render mode: {renderMode}", () => Browser.FindElement(By.Id("render-mode")).Text);
353+
Browser.Equal($"Streaming id:{streamingId}", () => Browser.FindElement(By.Id("streaming-id")).Text);
354+
Browser.Equal($"Interactive: {interactive}", () => Browser.FindElement(By.Id("interactive")).Text);
355+
if (streamingId == null || streamingCompleted)
356+
{
357+
interactiveRuntime = !interactive ? "none" : mode == "server" || mode == "wasm" ? mode : (interactiveRuntime ?? throw new InvalidOperationException("Specify interactiveRuntime for auto mode"));
358+
359+
Browser.Equal($"Interactive runtime: {interactiveRuntime}", () => Browser.FindElement(By.Id("interactive-runtime")).Text);
360+
Browser.Equal($"State value:{stateValue}", () => Browser.FindElement(By.Id("state-value")).Text);
361+
}
362+
else
363+
{
364+
Browser.Equal("Streaming: True", () => Browser.FindElement(By.Id("streaming")).Text);
365+
}
366+
}
351367
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
@page "/persistent-state/page-with-declarative-state-components"
2+
@using TestContentPackage.PersistentComponents
3+
4+
<h3>Declarative persistent component with enhanced navigation updates</h3>
5+
6+
<h3>
7+
This page can render one or more components with different render modes and different streaming rendering modes.
8+
It accepts a render-mode query parameter which is used to determine the render mode for the components on the page.
9+
It also accepts a streaming-id query parameter which is used to select whether to render a component that uses streaming rendering or not.
10+
The rendered components display the behavior of [UpdateOnEnhancedNavigation(true)] properties of [PersistentState]
11+
</h3>
12+
13+
<p id="render-mode">Render mode: @_renderMode?.GetType()?.Name</p>
14+
<p id="streaming-id">Streaming id:@StreamingId</p>
15+
@if (_renderMode != null)
16+
{
17+
@if (!string.IsNullOrEmpty(StreamingId))
18+
{
19+
<StreamingComponentWithDeclarativePersistentState @rendermode="@_renderMode" StreamingId="@StreamingId" ServerState="@ServerState" />
20+
}
21+
else
22+
{
23+
<NonStreamingComponentWithDeclarativePersistentState @rendermode="@_renderMode" ServerState="@ServerState" />
24+
}
25+
}
26+
@if (!string.IsNullOrEmpty(StreamingId))
27+
{
28+
<a id="end-streaming" href="@($"persistent-state/end-streaming?streaming-id={StreamingId}")" target="_blank">End streaming</a>
29+
}
30+
31+
<a id="page-no-components-link" href=@($"persistent-state/page-no-components?render-mode={RenderMode}&streaming-id={StreamingId}")>Go to page with no components</a>
32+
33+
34+
@code {
35+
36+
private IComponentRenderMode _renderMode;
37+
38+
[SupplyParameterFromQuery(Name = "render-mode")] public string RenderMode { get; set; }
39+
40+
[SupplyParameterFromQuery(Name = "streaming-id")] public string StreamingId { get; set; }
41+
42+
[SupplyParameterFromQuery(Name = "server-state")] public string ServerState { get; set; }
43+
44+
protected override void OnInitialized()
45+
{
46+
if (!string.IsNullOrEmpty(RenderMode))
47+
{
48+
switch (RenderMode)
49+
{
50+
case "server":
51+
_renderMode = new InteractiveServerRenderMode(true);
52+
break;
53+
case "wasm":
54+
_renderMode = new InteractiveWebAssemblyRenderMode(true);
55+
break;
56+
case "auto":
57+
_renderMode = new InteractiveAutoRenderMode(true);
58+
break;
59+
default:
60+
throw new ArgumentException($"Invalid render mode: {RenderMode}");
61+
}
62+
}
63+
}
64+
}

src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/PersistentState/PageWithoutComponents.razor

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
<a id="page-with-components-link-and-state" href=@($"persistent-state/page-with-components?render-mode={RenderMode}&streaming-id={StreamingId}&server-state=other")>Go to page with components and state</a>
88

9+
<a id="page-with-components-link-and-declarative-state" href=@($"persistent-state/page-with-declarative-state-components?render-mode={RenderMode}&streaming-id={StreamingId}&server-state=other")>Go to page with declarative state components</a>
910

1011
@code {
1112
[SupplyParameterFromQuery(Name = "render-mode")] public string RenderMode { get; set; }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<p>Non streaming component with persistent state</p>
2+
3+
<p>This component demonstrates state persistence in the absence of streaming rendering.
4+
When the component renders it will try to restore the state and if present display that
5+
it succeeded in doing so and the restored value.
6+
If the state is not present, it will indicate it didn't find it and display a "fresh"
7+
value.</p>
8+
9+
<p id="interactive">Interactive: @(RendererInfo.IsInteractive)</p>
10+
<p id="interactive-runtime">Interactive runtime: @_interactiveRuntime</p>
11+
<p id="state-value">State value:@EnhancedNavState</p>
12+
13+
<a id="enhanced-nav-update" href="@Navigation.GetUriWithQueryParameter("server-state", "updated")">With updated server state</a>
14+
<br />
15+
16+
@code {
17+
private string _interactiveRuntime;
18+
19+
[Inject] public PersistentComponentState PersistentComponentState { get; set; }
20+
[Inject] public NavigationManager Navigation { get; set; }
21+
22+
[Parameter] public string ServerState { get; set; }
23+
24+
[PersistentState]
25+
[UpdateStateOnEnhancedNavigation(true)]
26+
public string EnhancedNavState { get; set; }
27+
28+
protected override void OnInitialized()
29+
{
30+
if (!RendererInfo.IsInteractive)
31+
{
32+
_interactiveRuntime = "none";
33+
EnhancedNavState = ServerState;
34+
}
35+
else
36+
{
37+
EnhancedNavState ??= "not found";
38+
_interactiveRuntime = OperatingSystem.IsBrowser() ? "wasm" : "server";
39+
}
40+
}
41+
}

0 commit comments

Comments
 (0)