@@ -165,55 +165,58 @@ public void DisposeComponents()
165165 if ( disposed )
166166 throw new ObjectDisposedException ( nameof ( TestRenderer ) ) ;
167167
168- // The dispatcher will always return a completed task,
169- // when dealing with an IAsyncDisposable.
170- // Therefore checking for a completed task and awaiting it
171- // will only work on IDisposable
172- var disposeTask = Dispatcher . InvokeAsync ( ( ) =>
168+ lock ( renderTreeUpdateLock )
173169 {
174- ResetUnhandledException ( ) ;
175-
176- foreach ( var root in rootComponents )
170+ // The dispatcher will always return a completed task,
171+ // when dealing with an IAsyncDisposable.
172+ // Therefore checking for a completed task and awaiting it
173+ // will only work on IDisposable
174+ Dispatcher . InvokeAsync ( ( ) =>
177175 {
178- root . Detach ( ) ;
179- }
180- } ) ;
176+ ResetUnhandledException ( ) ;
181177
182- if ( ! disposeTask . IsCompleted )
183- {
184- disposeTask . GetAwaiter ( ) . GetResult ( ) ;
185- }
178+ foreach ( var root in rootComponents )
179+ {
180+ root . Detach ( ) ;
181+ }
182+ } ) ;
186183
187- rootComponents . Clear ( ) ;
188- AssertNoUnhandledExceptions ( ) ;
184+ rootComponents . Clear ( ) ;
185+ AssertNoUnhandledExceptions ( ) ;
186+ }
189187 }
190188
191189 /// <inheritdoc/>
192190 internal void SetDirectParameters ( IRenderedFragmentBase renderedComponent , ParameterView parameters )
193191 {
194- Dispatcher . InvokeAsync ( ( ) =>
192+ // Calling SetDirectParameters updates the render tree
193+ // if the event contains associated data.
194+ lock ( renderTreeUpdateLock )
195195 {
196- try
196+ Dispatcher . InvokeAsync ( ( ) =>
197197 {
198- IsBatchInProgress = true ;
198+ try
199+ {
200+ IsBatchInProgress = true ;
199201
200- var componentState = GetRequiredComponentStateMethod . Invoke ( this , new object [ ] { renderedComponent . ComponentId } ) ! ;
201- var setDirectParametersMethod = componentState . GetType ( ) . GetMethod ( "SetDirectParameters" , BindingFlags . Public | BindingFlags . Instance ) ! ;
202- setDirectParametersMethod . Invoke ( componentState , new object [ ] { parameters } ) ;
203- }
204- catch ( TargetInvocationException ex ) when ( ex . InnerException is not null )
205- {
206- HandleException ( ex . InnerException ) ;
207- }
208- finally
209- {
210- IsBatchInProgress = false ;
211- }
202+ var componentState = GetRequiredComponentStateMethod . Invoke ( this , new object [ ] { renderedComponent . ComponentId } ) ! ;
203+ var setDirectParametersMethod = componentState . GetType ( ) . GetMethod ( "SetDirectParameters" , BindingFlags . Public | BindingFlags . Instance ) ! ;
204+ setDirectParametersMethod . Invoke ( componentState , new object [ ] { parameters } ) ;
205+ }
206+ catch ( TargetInvocationException ex ) when ( ex . InnerException is not null )
207+ {
208+ HandleException ( ex . InnerException ) ;
209+ }
210+ finally
211+ {
212+ IsBatchInProgress = false ;
213+ }
212214
213- ProcessPendingRender ( ) ;
214- } ) ;
215+ ProcessPendingRender ( ) ;
216+ } ) ;
215217
216- AssertNoUnhandledExceptions ( ) ;
218+ AssertNoUnhandledExceptions ( ) ;
219+ }
217220 }
218221
219222 /// <inheritdoc/>
@@ -508,17 +511,23 @@ private void ResetUnhandledException()
508511
509512 private void AssertNoUnhandledExceptions ( )
510513 {
511- if ( capturedUnhandledException is Exception unhandled && ! disposed )
514+ // Ensure we are not throwing an exception while a render is ongoing.
515+ // This could lead to the renderer being disposed which could lead to
516+ // tests failing that should not be failing.
517+ lock ( renderTreeUpdateLock )
512518 {
513- capturedUnhandledException = null ;
514-
515- if ( unhandled is AggregateException aggregateException && aggregateException . InnerExceptions . Count == 1 )
516- {
517- ExceptionDispatchInfo . Capture ( aggregateException . InnerExceptions [ 0 ] ) . Throw ( ) ;
518- }
519- else
519+ if ( capturedUnhandledException is Exception unhandled && ! disposed )
520520 {
521- ExceptionDispatchInfo . Capture ( unhandled ) . Throw ( ) ;
521+ capturedUnhandledException = null ;
522+
523+ if ( unhandled is AggregateException aggregateException && aggregateException . InnerExceptions . Count == 1 )
524+ {
525+ ExceptionDispatchInfo . Capture ( aggregateException . InnerExceptions [ 0 ] ) . Throw ( ) ;
526+ }
527+ else
528+ {
529+ ExceptionDispatchInfo . Capture ( unhandled ) . Throw ( ) ;
530+ }
522531 }
523532 }
524533 }
0 commit comments