Ensure CircuitHost disposes DI scope even if other disposals throw
This commit is contained in:
parent
002cb51d72
commit
ee1cbda155
|
|
@ -293,10 +293,16 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
|||
|
||||
await Renderer.InvokeAsync(async () =>
|
||||
{
|
||||
await OnConnectionDownAsync(CancellationToken.None);
|
||||
await OnCircuitDownAsync();
|
||||
Renderer.Dispose();
|
||||
_scope.Dispose();
|
||||
try
|
||||
{
|
||||
await OnConnectionDownAsync(CancellationToken.None);
|
||||
await OnCircuitDownAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Renderer.Dispose();
|
||||
_scope.Dispose();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
|
@ -40,6 +41,37 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
|||
Assert.True(remoteRenderer.Disposed);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DisposeAsync_DisposesResourcesEvenIfCircuitHandlerOrComponentThrows()
|
||||
{
|
||||
// Arrange
|
||||
var serviceScope = new Mock<IServiceScope>();
|
||||
var handler = new Mock<CircuitHandler>();
|
||||
handler
|
||||
.Setup(h => h.OnCircuitClosedAsync(It.IsAny<Circuit>(), It.IsAny<CancellationToken>()))
|
||||
.Throws<InvalidTimeZoneException>();
|
||||
var remoteRenderer = GetRemoteRenderer(Renderer.CreateDefaultDispatcher());
|
||||
var circuitHost = TestCircuitHost.Create(
|
||||
Guid.NewGuid().ToString(),
|
||||
serviceScope.Object,
|
||||
remoteRenderer,
|
||||
handlers: new[] { handler.Object });
|
||||
|
||||
var throwOnDisposeComponent = new ThrowOnDisposeComponent();
|
||||
circuitHost.Renderer.AssignRootComponentId(throwOnDisposeComponent);
|
||||
|
||||
// Act
|
||||
await Assert.ThrowsAsync<InvalidTimeZoneException>(async () =>
|
||||
{
|
||||
await circuitHost.DisposeAsync();
|
||||
});
|
||||
|
||||
// Assert
|
||||
Assert.True(throwOnDisposeComponent.DidCallDispose);
|
||||
serviceScope.Verify(scope => scope.Dispose(), Times.Once());
|
||||
Assert.True(remoteRenderer.Disposed);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DisposeAsync_DisposesRendererWithinSynchronizationContext()
|
||||
{
|
||||
|
|
@ -239,5 +271,20 @@ namespace Microsoft.AspNetCore.Components.Server.Circuits
|
|||
Assert.Same(Dispatcher, SynchronizationContext.Current);
|
||||
}
|
||||
}
|
||||
|
||||
private class ThrowOnDisposeComponent : IComponent, IDisposable
|
||||
{
|
||||
public bool DidCallDispose { get; private set; }
|
||||
public void Configure(RenderHandle renderHandle) { }
|
||||
|
||||
public Task SetParametersAsync(ParameterCollection parameters)
|
||||
=> Task.CompletedTask;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
DidCallDispose = true;
|
||||
throw new InvalidFilterCriteriaException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue