@@ -16,45 +16,23 @@ internal partial class CircuitPersistenceManager(
16
16
ServerComponentSerializer serverComponentSerializer ,
17
17
ICircuitPersistenceProvider circuitPersistenceProvider )
18
18
{
19
- private const string CircuitPersistenceManagerKey = $ "Microsoft.AspNetCore.Components.Server.Circuits.{ nameof ( CircuitPersistenceManager ) } ";
20
-
21
19
public async Task PauseCircuitAsync ( CircuitHost circuit , CancellationToken cancellation = default )
22
20
{
23
21
var renderer = circuit . Renderer ;
24
22
var persistenceManager = circuit . Services . GetRequiredService < ComponentStatePersistenceManager > ( ) ;
23
+ var collector = new CircuitPersistenceManagerCollector ( circuitOptions , serverComponentSerializer , circuit . Renderer ) ;
25
24
using var subscription = persistenceManager . State . RegisterOnPersisting (
26
- ( ) => PersistRootComponents ( renderer , persistenceManager . State ) ,
25
+ collector . PersistRootComponents ,
27
26
RenderMode . InteractiveServer ) ;
28
- var store = new CircuitPersistenceManagerStore ( ) ;
29
- await persistenceManager . PersistStateAsync ( store , renderer ) ;
27
+
28
+ await persistenceManager . PersistStateAsync ( collector , renderer ) ;
30
29
31
30
await circuitPersistenceProvider . PersistCircuitAsync (
32
31
circuit . CircuitId ,
33
- store . PersistedCircuitState ,
32
+ collector . PersistedCircuitState ,
34
33
cancellation ) ;
35
34
}
36
35
37
- private Task PersistRootComponents ( RemoteRenderer renderer , PersistentComponentState state )
38
- {
39
- var persistedComponents = new Dictionary < int , ComponentMarker > ( ) ;
40
- var components = renderer . GetOrCreateWebRootComponentManager ( ) . GetRootComponents ( ) ;
41
- var invocation = new ServerComponentInvocationSequence ( ) ;
42
- foreach ( var ( id , componentKey , ( componentType , parameters ) ) in components )
43
- {
44
- var distributedRetention = circuitOptions . Value . PersistedCircuitInMemoryRetentionPeriod ;
45
- var localRetention = circuitOptions . Value . PersistedCircuitInMemoryRetentionPeriod ;
46
- var maxRetention = distributedRetention > localRetention ? distributedRetention : localRetention ;
47
-
48
- var marker = ComponentMarker . Create ( ComponentMarker . ServerMarkerType , false , componentKey ) ;
49
- serverComponentSerializer . SerializeInvocation ( ref marker , invocation , componentType , parameters , maxRetention ) ;
50
- persistedComponents . Add ( id , marker ) ;
51
- }
52
-
53
- state . PersistAsJson ( CircuitPersistenceManagerKey , persistedComponents ) ;
54
-
55
- return Task . CompletedTask ;
56
- }
57
-
58
36
public async Task < PersistedCircuitState > ResumeCircuitAsync ( CircuitId circuitId , CancellationToken cancellation = default )
59
37
{
60
38
return await circuitPersistenceProvider . RestoreCircuitAsync ( circuitId , cancellation ) ;
@@ -63,7 +41,7 @@ public async Task<PersistedCircuitState> ResumeCircuitAsync(CircuitId circuitId,
63
41
// We are going to construct a RootComponentOperationBatch but we are going to replace the descriptors from the client with the
64
42
// descriptors that we have persisted when pausing the circuit.
65
43
// The way pausing and resuming works is that when the client starts the resume process, it 'simulates' that an SSR has happened and
66
- // queues and 'Add' operation for each server-side component that is on the document.
44
+ // queues an 'Add' operation for each server-side component that is on the document.
67
45
// That ends up calling UpdateRootComponents with the old descriptors and no application state.
68
46
// On the server side, we replace the descriptors with the ones that we have persisted. We can't use the original descriptors because
69
47
// those have a lifetime of ~ 5 minutes, after which we are not able to unprotect them anymore.
@@ -139,10 +117,40 @@ static Dictionary<int, ComponentMarker> TryDeserializeMarkers(byte[] rootCompone
139
117
}
140
118
}
141
119
142
- private class CircuitPersistenceManagerStore : IPersistentComponentStateStore
120
+ private class CircuitPersistenceManagerCollector (
121
+ IOptions < CircuitOptions > circuitOptions ,
122
+ ServerComponentSerializer serverComponentSerializer ,
123
+ RemoteRenderer renderer )
124
+ : IPersistentComponentStateStore
143
125
{
144
126
internal PersistedCircuitState PersistedCircuitState { get ; private set ; }
145
127
128
+ public Task PersistRootComponents ( )
129
+ {
130
+ var persistedComponents = new Dictionary < int , ComponentMarker > ( ) ;
131
+ var components = renderer . GetOrCreateWebRootComponentManager ( ) . GetRootComponents ( ) ;
132
+ var invocation = new ServerComponentInvocationSequence ( ) ;
133
+ foreach ( var ( id , componentKey , ( componentType , parameters ) ) in components )
134
+ {
135
+ var distributedRetention = circuitOptions . Value . PersistedCircuitInMemoryRetentionPeriod ;
136
+ var localRetention = circuitOptions . Value . PersistedCircuitInMemoryRetentionPeriod ;
137
+ var maxRetention = distributedRetention > localRetention ? distributedRetention : localRetention ;
138
+
139
+ var marker = ComponentMarker . Create ( ComponentMarker . ServerMarkerType , prerendered : false , componentKey ) ;
140
+ serverComponentSerializer . SerializeInvocation ( ref marker , invocation , componentType , parameters , maxRetention ) ;
141
+ persistedComponents . Add ( id , marker ) ;
142
+ }
143
+
144
+ PersistedCircuitState = new PersistedCircuitState
145
+ {
146
+ RootComponents = JsonSerializer . SerializeToUtf8Bytes (
147
+ persistedComponents ,
148
+ CircuitPersistenceManagerSerializerContext . Default . DictionaryInt32ComponentMarker )
149
+ } ;
150
+
151
+ return Task . CompletedTask ;
152
+ }
153
+
146
154
// This store only support serializing the state
147
155
Task < IDictionary < string , byte [ ] > > IPersistentComponentStateStore . GetPersistedStateAsync ( ) => throw new NotImplementedException ( ) ;
148
156
@@ -152,26 +160,7 @@ private class CircuitPersistenceManagerStore : IPersistentComponentStateStore
152
160
// and store them separately from the other state.
153
161
Task IPersistentComponentStateStore . PersistStateAsync ( IReadOnlyDictionary < string , byte [ ] > state )
154
162
{
155
- var dictionary = new Dictionary < string , byte [ ] > ( state . Count - 1 ) ;
156
- byte [ ] rootComponentMarkers = null ;
157
- foreach ( var ( key , value ) in state )
158
- {
159
- if ( key == CircuitPersistenceManagerKey )
160
- {
161
- rootComponentMarkers = value ;
162
- }
163
- else
164
- {
165
- dictionary [ key ] = value ;
166
- }
167
- }
168
-
169
- PersistedCircuitState = new PersistedCircuitState
170
- {
171
- ApplicationState = dictionary ,
172
- RootComponents = rootComponentMarkers
173
- } ;
174
-
163
+ PersistedCircuitState . ApplicationState = state ;
175
164
return Task . CompletedTask ;
176
165
}
177
166
}
0 commit comments