@@ -16,45 +16,23 @@ internal partial class CircuitPersistenceManager(
1616 ServerComponentSerializer serverComponentSerializer ,
1717 ICircuitPersistenceProvider circuitPersistenceProvider )
1818{
19- private const string CircuitPersistenceManagerKey = $ "Microsoft.AspNetCore.Components.Server.Circuits.{ nameof ( CircuitPersistenceManager ) } ";
20-
2119 public async Task PauseCircuitAsync ( CircuitHost circuit , CancellationToken cancellation = default )
2220 {
2321 var renderer = circuit . Renderer ;
2422 var persistenceManager = circuit . Services . GetRequiredService < ComponentStatePersistenceManager > ( ) ;
23+ var collector = new CircuitPersistenceManagerCollector ( circuitOptions , serverComponentSerializer , circuit . Renderer ) ;
2524 using var subscription = persistenceManager . State . RegisterOnPersisting (
26- ( ) => PersistRootComponents ( renderer , persistenceManager . State ) ,
25+ collector . PersistRootComponents ,
2726 RenderMode . InteractiveServer ) ;
28- var store = new CircuitPersistenceManagerStore ( ) ;
29- await persistenceManager . PersistStateAsync ( store , renderer ) ;
27+
28+ await persistenceManager . PersistStateAsync ( collector , renderer ) ;
3029
3130 await circuitPersistenceProvider . PersistCircuitAsync (
3231 circuit . CircuitId ,
33- store . PersistedCircuitState ,
32+ collector . PersistedCircuitState ,
3433 cancellation ) ;
3534 }
3635
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-
5836 public async Task < PersistedCircuitState > ResumeCircuitAsync ( CircuitId circuitId , CancellationToken cancellation = default )
5937 {
6038 return await circuitPersistenceProvider . RestoreCircuitAsync ( circuitId , cancellation ) ;
@@ -63,7 +41,7 @@ public async Task<PersistedCircuitState> ResumeCircuitAsync(CircuitId circuitId,
6341 // We are going to construct a RootComponentOperationBatch but we are going to replace the descriptors from the client with the
6442 // descriptors that we have persisted when pausing the circuit.
6543 // 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.
6745 // That ends up calling UpdateRootComponents with the old descriptors and no application state.
6846 // On the server side, we replace the descriptors with the ones that we have persisted. We can't use the original descriptors because
6947 // 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
139117 }
140118 }
141119
142- private class CircuitPersistenceManagerStore : IPersistentComponentStateStore
120+ private class CircuitPersistenceManagerCollector (
121+ IOptions < CircuitOptions > circuitOptions ,
122+ ServerComponentSerializer serverComponentSerializer ,
123+ RemoteRenderer renderer )
124+ : IPersistentComponentStateStore
143125 {
144126 internal PersistedCircuitState PersistedCircuitState { get ; private set ; }
145127
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+
146154 // This store only support serializing the state
147155 Task < IDictionary < string , byte [ ] > > IPersistentComponentStateStore . GetPersistedStateAsync ( ) => throw new NotImplementedException ( ) ;
148156
@@ -152,26 +160,7 @@ private class CircuitPersistenceManagerStore : IPersistentComponentStateStore
152160 // and store them separately from the other state.
153161 Task IPersistentComponentStateStore . PersistStateAsync ( IReadOnlyDictionary < string , byte [ ] > state )
154162 {
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 ;
175164 return Task . CompletedTask ;
176165 }
177166 }
0 commit comments