@@ -155,55 +155,58 @@ public void DisposeComponents()
155155 if ( disposed )
156156 throw new ObjectDisposedException ( nameof ( TestRenderer ) ) ;
157157
158- // The dispatcher will always return a completed task,
159- // when dealing with an IAsyncDisposable.
160- // Therefore checking for a completed task and awaiting it
161- // will only work on IDisposable
162- var disposeTask = Dispatcher . InvokeAsync ( ( ) =>
158+ lock ( renderTreeUpdateLock )
163159 {
164- ResetUnhandledException ( ) ;
165-
166- foreach ( var root in rootComponents )
160+ // The dispatcher will always return a completed task,
161+ // when dealing with an IAsyncDisposable.
162+ // Therefore checking for a completed task and awaiting it
163+ // will only work on IDisposable
164+ Dispatcher . InvokeAsync ( ( ) =>
167165 {
168- root . Detach ( ) ;
169- }
170- } ) ;
166+ ResetUnhandledException ( ) ;
171167
172- if ( ! disposeTask . IsCompleted )
173- {
174- disposeTask . GetAwaiter ( ) . GetResult ( ) ;
175- }
168+ foreach ( var root in rootComponents )
169+ {
170+ root . Detach ( ) ;
171+ }
172+ } ) ;
176173
177- rootComponents . Clear ( ) ;
178- AssertNoUnhandledExceptions ( ) ;
174+ rootComponents . Clear ( ) ;
175+ AssertNoUnhandledExceptions ( ) ;
176+ }
179177 }
180178
181179 /// <inheritdoc/>
182180 internal void SetDirectParameters ( IRenderedFragmentBase renderedComponent , ParameterView parameters )
183181 {
184- Dispatcher . InvokeAsync ( ( ) =>
182+ // Calling SetDirectParameters updates the render tree
183+ // if the event contains associated data.
184+ lock ( renderTreeUpdateLock )
185185 {
186- try
186+ Dispatcher . InvokeAsync ( ( ) =>
187187 {
188- IsBatchInProgress = true ;
188+ try
189+ {
190+ IsBatchInProgress = true ;
189191
190- var componentState = GetRequiredComponentStateMethod . Invoke ( this , new object [ ] { renderedComponent . ComponentId } ) ! ;
191- var setDirectParametersMethod = componentState . GetType ( ) . GetMethod ( "SetDirectParameters" , BindingFlags . Public | BindingFlags . Instance ) ! ;
192- setDirectParametersMethod . Invoke ( componentState , new object [ ] { parameters } ) ;
193- }
194- catch ( TargetInvocationException ex ) when ( ex . InnerException is not null )
195- {
196- HandleException ( ex . InnerException ) ;
197- }
198- finally
199- {
200- IsBatchInProgress = false ;
201- }
192+ var componentState = GetRequiredComponentStateMethod . Invoke ( this , new object [ ] { renderedComponent . ComponentId } ) ! ;
193+ var setDirectParametersMethod = componentState . GetType ( ) . GetMethod ( "SetDirectParameters" , BindingFlags . Public | BindingFlags . Instance ) ! ;
194+ setDirectParametersMethod . Invoke ( componentState , new object [ ] { parameters } ) ;
195+ }
196+ catch ( TargetInvocationException ex ) when ( ex . InnerException is not null )
197+ {
198+ HandleException ( ex . InnerException ) ;
199+ }
200+ finally
201+ {
202+ IsBatchInProgress = false ;
203+ }
202204
203- ProcessPendingRender ( ) ;
204- } ) ;
205+ ProcessPendingRender ( ) ;
206+ } ) ;
205207
206- AssertNoUnhandledExceptions ( ) ;
208+ AssertNoUnhandledExceptions ( ) ;
209+ }
207210 }
208211
209212 /// <inheritdoc/>
@@ -498,17 +501,23 @@ private void ResetUnhandledException()
498501
499502 private void AssertNoUnhandledExceptions ( )
500503 {
501- if ( capturedUnhandledException is Exception unhandled && ! disposed )
504+ // Ensure we are not throwing an exception while a render is ongoing.
505+ // This could lead to the renderer being disposed which could lead to
506+ // tests failing that should not be failing.
507+ lock ( renderTreeUpdateLock )
502508 {
503- capturedUnhandledException = null ;
504-
505- if ( unhandled is AggregateException aggregateException && aggregateException . InnerExceptions . Count == 1 )
506- {
507- ExceptionDispatchInfo . Capture ( aggregateException . InnerExceptions [ 0 ] ) . Throw ( ) ;
508- }
509- else
509+ if ( capturedUnhandledException is Exception unhandled && ! disposed )
510510 {
511- ExceptionDispatchInfo . Capture ( unhandled ) . Throw ( ) ;
511+ capturedUnhandledException = null ;
512+
513+ if ( unhandled is AggregateException aggregateException && aggregateException . InnerExceptions . Count == 1 )
514+ {
515+ ExceptionDispatchInfo . Capture ( aggregateException . InnerExceptions [ 0 ] ) . Throw ( ) ;
516+ }
517+ else
518+ {
519+ ExceptionDispatchInfo . Capture ( unhandled ) . Throw ( ) ;
520+ }
512521 }
513522 }
514523 }
0 commit comments