diff --git a/src/Servers/IIS/IIS/src/Core/IISHttpContext.cs b/src/Servers/IIS/IIS/src/Core/IISHttpContext.cs index 5103ae871d..61f808fd12 100644 --- a/src/Servers/IIS/IIS/src/Core/IISHttpContext.cs +++ b/src/Servers/IIS/IIS/src/Core/IISHttpContext.cs @@ -411,7 +411,7 @@ namespace Microsoft.AspNetCore.Server.IIS.Core } } - public abstract Task ProcessRequestAsync(); + public abstract Task ProcessRequestAsync(); public void OnStarting(Func callback, object state) { @@ -601,9 +601,10 @@ namespace Microsoft.AspNetCore.Server.IIS.Core private async Task HandleRequest() { + bool successfulRequest = false; try { - await ProcessRequestAsync(); + successfulRequest = await ProcessRequestAsync(); } catch (Exception ex) { @@ -611,9 +612,19 @@ namespace Microsoft.AspNetCore.Server.IIS.Core } finally { + // Post completion after completing the request to resume the state machine + PostCompletion(ConvertRequestCompletionResults(successfulRequest)); + + // Dispose the context Dispose(); } } + + private static NativeMethods.REQUEST_NOTIFICATION_STATUS ConvertRequestCompletionResults(bool success) + { + return success ? NativeMethods.REQUEST_NOTIFICATION_STATUS.RQ_NOTIFICATION_CONTINUE + : NativeMethods.REQUEST_NOTIFICATION_STATUS.RQ_NOTIFICATION_FINISH_REQUEST; + } } } diff --git a/src/Servers/IIS/IIS/src/Core/IISHttpContextOfT.cs b/src/Servers/IIS/IIS/src/Core/IISHttpContextOfT.cs index cfdc20b225..ecd3a86e75 100644 --- a/src/Servers/IIS/IIS/src/Core/IISHttpContextOfT.cs +++ b/src/Servers/IIS/IIS/src/Core/IISHttpContextOfT.cs @@ -23,33 +23,32 @@ namespace Microsoft.AspNetCore.Server.IIS.Core _application = application; } - public override async Task ProcessRequestAsync() + public override async Task ProcessRequestAsync() { + InitializeContext(); + var context = default(TContext); var success = true; try { - InitializeContext(); - - try - { - context = _application.CreateContext(this); - - await _application.ProcessRequestAsync(context); - } - catch (BadHttpRequestException ex) - { - SetBadRequestState(ex); - ReportApplicationError(ex); - success = false; - } - catch (Exception ex) - { - ReportApplicationError(ex); - success = false; - } + context = _application.CreateContext(this); + await _application.ProcessRequestAsync(context); + } + catch (BadHttpRequestException ex) + { + SetBadRequestState(ex); + ReportApplicationError(ex); + success = false; + } + catch (Exception ex) + { + ReportApplicationError(ex); + success = false; + } + finally + { await CompleteResponseBodyAsync(); _streams.Stop(); @@ -59,18 +58,36 @@ namespace Microsoft.AspNetCore.Server.IIS.Core // Dispose } - if (!_requestAborted) + if (_onCompleted != null) { - await ProduceEnd(); - } - else if (!HasResponseStarted && _requestRejectedException == null) - { - // If the request was aborted and no response was sent, there's no - // meaningful status code to log. - StatusCode = 0; - success = false; + await FireOnCompleted(); } + } + if (!_requestAborted) + { + await ProduceEnd(); + } + else if (!HasResponseStarted && _requestRejectedException == null) + { + // If the request was aborted and no response was sent, there's no + // meaningful status code to log. + StatusCode = 0; + success = false; + } + + try + { + _application.DisposeContext(context, _applicationException); + } + catch (Exception ex) + { + // TODO Log this + _applicationException = _applicationException ?? ex; + success = false; + } + finally + { // Complete response writer and request reader pipe sides _bodyOutput.Dispose(); _bodyInputPipe?.Reader.Complete(); @@ -89,36 +106,7 @@ namespace Microsoft.AspNetCore.Server.IIS.Core await _readBodyTask; } } - catch (Exception ex) - { - success = false; - ReportApplicationError(ex); - } - finally - { - // We're done with anything that touches the request or response, unblock the client. - PostCompletion(ConvertRequestCompletionResults(success)); - - if (_onCompleted != null) - { - await FireOnCompleted(); - } - - try - { - _application.DisposeContext(context, _applicationException); - } - catch (Exception ex) - { - ReportApplicationError(ex); - } - } - } - - private static NativeMethods.REQUEST_NOTIFICATION_STATUS ConvertRequestCompletionResults(bool success) - { - return success ? NativeMethods.REQUEST_NOTIFICATION_STATUS.RQ_NOTIFICATION_CONTINUE - : NativeMethods.REQUEST_NOTIFICATION_STATUS.RQ_NOTIFICATION_FINISH_REQUEST; + return success; } } } diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Inprocess/ResponseBodyTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Inprocess/ResponseBodyTests.cs index d1867c8044..d45024441e 100644 --- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Inprocess/ResponseBodyTests.cs +++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Inprocess/ResponseBodyTests.cs @@ -30,12 +30,5 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.InProcess { Assert.Equal(20, (await _fixture.Client.GetByteArrayAsync($"/FlushedPipeAndThenUnflushedPipe")).Length); } - - [ConditionalFact] - [RequiresNewHandler] - public async Task ResponseBodyTest_BodyCompletionNotBlockedByOnCompleted() - { - Assert.Equal("SlowOnCompleted", await _fixture.Client.GetStringAsync($"/SlowOnCompleted")); - } } } diff --git a/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/Startup.cs b/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/Startup.cs index 95ae863ffd..b2ee3c1456 100644 --- a/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/Startup.cs +++ b/src/Servers/IIS/IIS/test/testassets/InProcessWebSite/Startup.cs @@ -1016,12 +1016,5 @@ namespace TestSite await context.Response.WriteAsync(httpsPort.HasValue ? httpsPort.Value.ToString() : "NOVALUE"); } - - public async Task SlowOnCompleted(HttpContext context) - { - // This shouldn't block the response or the server from shutting down. - context.Response.OnCompleted(() => Task.Delay(TimeSpan.FromMinutes(5))); - await context.Response.WriteAsync("SlowOnCompleted"); - } } }