@@ -22,7 +22,7 @@ internal partial class CircuitHost : IAsyncDisposable
22
22
private readonly CircuitOptions _options ;
23
23
private readonly RemoteNavigationManager _navigationManager ;
24
24
private readonly ILogger _logger ;
25
- private readonly Func < Func < Task > , Task > _dispatchInboundActivity ;
25
+ private Func < Func < Task > , Task > _dispatchInboundActivity ;
26
26
private CircuitHandler [ ] _circuitHandlers ;
27
27
private bool _initialized ;
28
28
private bool _isFirstUpdate = true ;
@@ -735,11 +735,10 @@ internal Task UpdateRootComponents(
735
735
736
736
return Renderer . Dispatcher . InvokeAsync ( async ( ) =>
737
737
{
738
- var webRootComponentManager = Renderer . GetOrCreateWebRootComponentManager ( ) ;
739
738
var shouldClearStore = false ;
739
+ var shouldWaitForQuiescence = false ;
740
740
var operations = operationBatch . Operations ;
741
741
var batchId = operationBatch . BatchId ;
742
- Task [ ] ? pendingTasks = null ;
743
742
try
744
743
{
745
744
if ( Descriptors . Count > 0 )
@@ -752,6 +751,7 @@ internal Task UpdateRootComponents(
752
751
if ( _isFirstUpdate )
753
752
{
754
753
_isFirstUpdate = false ;
754
+ shouldWaitForQuiescence = true ;
755
755
if ( store != null )
756
756
{
757
757
shouldClearStore = true ;
@@ -763,6 +763,7 @@ internal Task UpdateRootComponents(
763
763
764
764
// Retrieve the circuit handlers at this point.
765
765
_circuitHandlers = [ .. _scope . ServiceProvider . GetServices < CircuitHandler > ( ) . OrderBy ( h => h . Order ) ] ;
766
+ _dispatchInboundActivity = BuildInboundActivityDispatcher ( _circuitHandlers , Circuit ) ;
766
767
await OnCircuitOpenedAsync ( cancellation ) ;
767
768
await OnConnectionUpAsync ( cancellation ) ;
768
769
@@ -774,44 +775,9 @@ internal Task UpdateRootComponents(
774
775
throw new InvalidOperationException ( $ "The first set of update operations must always be of type { nameof ( RootComponentOperationType . Add ) } ") ;
775
776
}
776
777
}
777
-
778
- pendingTasks = new Task [ operations . Length ] ;
779
- }
780
-
781
- for ( var i = 0 ; i < operations . Length ; i ++ )
782
- {
783
- var operation = operations [ i ] ;
784
- switch ( operation . Type )
785
- {
786
- case RootComponentOperationType . Add :
787
- var task = webRootComponentManager . AddRootComponentAsync (
788
- operation . SsrComponentId ,
789
- operation . Descriptor . ComponentType ,
790
- operation . Marker . Value . Key ,
791
- operation . Descriptor . Parameters ) ;
792
- if ( pendingTasks != null )
793
- {
794
- pendingTasks [ i ] = task ;
795
- }
796
- break ;
797
- case RootComponentOperationType . Update :
798
- // We don't need to await component updates as any unhandled exception will be reported and terminate the circuit.
799
- _ = webRootComponentManager . UpdateRootComponentAsync (
800
- operation . SsrComponentId ,
801
- operation . Descriptor . ComponentType ,
802
- operation . Marker . Value . Key ,
803
- operation . Descriptor . Parameters ) ;
804
- break ;
805
- case RootComponentOperationType . Remove :
806
- webRootComponentManager . RemoveRootComponent ( operation . SsrComponentId ) ;
807
- break ;
808
- }
809
778
}
810
779
811
- if ( pendingTasks != null )
812
- {
813
- await Task . WhenAll ( pendingTasks ) ;
814
- }
780
+ await PerformRootComponentOperations ( operations , shouldWaitForQuiescence ) ;
815
781
816
782
await Client . SendAsync ( "JS.EndUpdateRootComponents" , batchId ) ;
817
783
@@ -837,6 +803,58 @@ internal Task UpdateRootComponents(
837
803
} ) ;
838
804
}
839
805
806
+ private async ValueTask PerformRootComponentOperations (
807
+ RootComponentOperation [ ] operations ,
808
+ bool shouldWaitForQuiescence )
809
+ {
810
+ var webRootComponentManager = Renderer . GetOrCreateWebRootComponentManager ( ) ;
811
+ var pendingTasks = shouldWaitForQuiescence
812
+ ? new Task [ operations . Length ]
813
+ : null ;
814
+
815
+ // The inbound activity pipeline needs to be awaited because it populates
816
+ // the pending tasks used to wait for quiescence.
817
+ await HandleInboundActivityAsync ( ( ) =>
818
+ {
819
+ for ( var i = 0 ; i < operations . Length ; i ++ )
820
+ {
821
+ var operation = operations [ i ] ;
822
+ switch ( operation . Type )
823
+ {
824
+ case RootComponentOperationType . Add :
825
+ var task = webRootComponentManager . AddRootComponentAsync (
826
+ operation . SsrComponentId ,
827
+ operation . Descriptor . ComponentType ,
828
+ operation . Marker . Value . Key ,
829
+ operation . Descriptor . Parameters ) ;
830
+ if ( pendingTasks != null )
831
+ {
832
+ pendingTasks [ i ] = task ;
833
+ }
834
+ break ;
835
+ case RootComponentOperationType . Update :
836
+ // We don't need to await component updates as any unhandled exception will be reported and terminate the circuit.
837
+ _ = webRootComponentManager . UpdateRootComponentAsync (
838
+ operation . SsrComponentId ,
839
+ operation . Descriptor . ComponentType ,
840
+ operation . Marker . Value . Key ,
841
+ operation . Descriptor . Parameters ) ;
842
+ break ;
843
+ case RootComponentOperationType . Remove :
844
+ webRootComponentManager . RemoveRootComponent ( operation . SsrComponentId ) ;
845
+ break ;
846
+ }
847
+ }
848
+
849
+ return Task . CompletedTask ;
850
+ } ) ;
851
+
852
+ if ( pendingTasks != null )
853
+ {
854
+ await Task . WhenAll ( pendingTasks ) ;
855
+ }
856
+ }
857
+
840
858
private static partial class Log
841
859
{
842
860
// 100s used for lifecycle stuff
0 commit comments