diff --git a/src/Components/Server/src/Circuits/CircuitHost.cs b/src/Components/Server/src/Circuits/CircuitHost.cs index 8010f1174dec..0f0cbceafb4e 100644 --- a/src/Components/Server/src/Circuits/CircuitHost.cs +++ b/src/Components/Server/src/Circuits/CircuitHost.cs @@ -170,7 +170,18 @@ await Renderer.Dispatcher.InvokeAsync(async () => try { Renderer.Dispose(); - _scope.Dispose(); + + // This cast is needed because it's possible the scope may not support async dispose. + // Our DI container does, but other DI systems may not. + if (_scope is IAsyncDisposable asyncDisposable) + { + await asyncDisposable.DisposeAsync(); + } + else + { + _scope.Dispose(); + } + Log.DisposeSucceeded(_logger, CircuitId); } catch (Exception ex) diff --git a/src/Components/Server/test/Circuits/CircuitHostTest.cs b/src/Components/Server/test/Circuits/CircuitHostTest.cs index f85a408803ae..dc4d5da01f90 100644 --- a/src/Components/Server/test/Circuits/CircuitHostTest.cs +++ b/src/Components/Server/test/Circuits/CircuitHostTest.cs @@ -39,6 +39,33 @@ public async Task DisposeAsync_DisposesResources() Assert.Null(circuitHost.Handle.CircuitHost); } + [Fact] + public async Task DisposeAsync_DisposesScopeAsynchronouslyIfPossible() + { + // Arrange + var serviceScope = new Mock(); + serviceScope + .As() + .Setup(f => f.DisposeAsync()) + .Returns(new ValueTask(Task.CompletedTask)) + .Verifiable(); + + var remoteRenderer = GetRemoteRenderer(); + var circuitHost = TestCircuitHost.Create( + Guid.NewGuid().ToString(), + serviceScope.Object, + remoteRenderer); + + // Act + await circuitHost.DisposeAsync(); + + // Assert + serviceScope.Verify(s => s.Dispose(), Times.Never()); + serviceScope.As().Verify(s => s.DisposeAsync(), Times.Once()); + Assert.True(remoteRenderer.Disposed); + Assert.Null(circuitHost.Handle.CircuitHost); + } + [Fact] public async Task DisposeAsync_DisposesResourcesAndSilencesException() {