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