diff --git a/src/Http/Http/src/Internal/DefaultHttpResponse.cs b/src/Http/Http/src/Internal/DefaultHttpResponse.cs index 55cbbb4df3..27e2cf744c 100644 --- a/src/Http/Http/src/Internal/DefaultHttpResponse.cs +++ b/src/Http/Http/src/Internal/DefaultHttpResponse.cs @@ -151,6 +151,11 @@ namespace Microsoft.AspNetCore.Http.Internal public override Task StartAsync(CancellationToken cancellationToken = default) { + if (HasStarted) + { + return Task.CompletedTask; + } + if (HttpResponseStartFeature == null) { return HttpResponseFeature.Body.FlushAsync(cancellationToken); diff --git a/src/Http/Http/test/Internal/DefaultHttpResponseTests.cs b/src/Http/Http/test/Internal/DefaultHttpResponseTests.cs index 1dbab3587f..bd7e2aff04 100644 --- a/src/Http/Http/test/Internal/DefaultHttpResponseTests.cs +++ b/src/Http/Http/test/Internal/DefaultHttpResponseTests.cs @@ -110,6 +110,10 @@ namespace Microsoft.AspNetCore.Http.Internal mock.Setup(o => o.StartAsync(It.IsAny())).Returns(Task.CompletedTask); features.Set(mock.Object); + var responseMock = new Mock(); + responseMock.Setup(o => o.HasStarted).Returns(false); + features.Set(responseMock.Object); + var context = new DefaultHttpContext(features); await context.Response.StartAsync(); @@ -126,12 +130,35 @@ namespace Microsoft.AspNetCore.Http.Internal mock.Setup(o => o.StartAsync(It.Is((localCt) => localCt.Equals(ct)))).Returns(Task.CompletedTask); features.Set(mock.Object); + var responseMock = new Mock(); + responseMock.Setup(o => o.HasStarted).Returns(false); + features.Set(responseMock.Object); + var context = new DefaultHttpContext(features); await context.Response.StartAsync(ct); mock.Verify(m => m.StartAsync(default), Times.Once()); } + [Fact] + public async Task ResponseStart_DoesNotCallStartIfHasStartedIsTrue() + { + var features = new FeatureCollection(); + + var startMock = new Mock(); + startMock.Setup(o => o.StartAsync(It.IsAny())).Returns(Task.CompletedTask); + features.Set(startMock.Object); + + var responseMock = new Mock(); + responseMock.Setup(o => o.HasStarted).Returns(true); + features.Set(responseMock.Object); + + var context = new DefaultHttpContext(features); + await context.Response.StartAsync(); + + startMock.Verify(m => m.StartAsync(default), Times.Never()); + } + [Fact] public async Task ResponseStart_CallsResponseBodyFlushIfNotSet() {