diff --git a/src/Http/Routing/src/EndpointRoutingMiddleware.cs b/src/Http/Routing/src/EndpointRoutingMiddleware.cs index cfaff0befb..65596ecfd4 100644 --- a/src/Http/Routing/src/EndpointRoutingMiddleware.cs +++ b/src/Http/Routing/src/EndpointRoutingMiddleware.cs @@ -52,7 +52,7 @@ namespace Microsoft.AspNetCore.Routing { Log.MatchSkipped(_logger, endpoint); - // Someone else set the endpoint, we'll let them handle the unsetting. + // Someone else set the endpoint, we'll let them handle the clearing of the endpoint. return _next(httpContext); } @@ -88,7 +88,6 @@ namespace Microsoft.AspNetCore.Routing } - [MethodImpl(MethodImplOptions.AggressiveInlining)] private async Task SetRoutingAndContinue(HttpContext httpContext) { // If there was no mutation of the endpoint then log failure @@ -115,8 +114,7 @@ namespace Microsoft.AspNetCore.Routing } finally { - // We unset the endpoint after calling through to the next middleware. This enables any future calls into - // endpoint routing don't no-op from there already being an endpoint set. + // This allows a second call in a single request (such as from the ErrorHandlerMiddleware) to perform routing again. httpContext.SetEndpoint(endpoint: null); } } diff --git a/src/Http/Routing/test/UnitTests/EndpointRoutingMiddlewareTest.cs b/src/Http/Routing/test/UnitTests/EndpointRoutingMiddlewareTest.cs index b2e08d9a2c..c3cf38cc32 100644 --- a/src/Http/Routing/test/UnitTests/EndpointRoutingMiddlewareTest.cs +++ b/src/Http/Routing/test/UnitTests/EndpointRoutingMiddlewareTest.cs @@ -20,6 +20,48 @@ namespace Microsoft.AspNetCore.Routing { public class EndpointRoutingMiddlewareTest { + [Fact] + public async Task Invoke_ChangedPath_ResultsInDifferentResult() + { + // Arrange + var httpContext = CreateHttpContext(); + var matcher = new Mock(); + var pathToEndpoints = new Dictionary() + { + ["/initial"] = new Endpoint(c => Task.CompletedTask, new EndpointMetadataCollection(), "initialEndpoint"), + ["/changed"] = new Endpoint(c => Task.CompletedTask, new EndpointMetadataCollection(), "changedEndpoint") + }; + matcher.Setup(m => m.MatchAsync(httpContext)) + .Callback(context => + { + var endpointToSet = pathToEndpoints[context.Request.Path]; + context.SetEndpoint(endpointToSet); + }) + .Returns(Task.CompletedTask) + .Verifiable(); + var matcherFactory = Mock.Of(factory => factory.CreateMatcher(It.IsAny()) == matcher.Object); + var middleware = CreateMiddleware( + matcherFactory: matcherFactory, + next: context => + { + Assert.True(pathToEndpoints.TryGetValue(context.Request.Path, out var expectedEndpoint)); + + var currentEndpoint = context.GetEndpoint(); + Assert.Equal(expectedEndpoint, currentEndpoint); + + return Task.CompletedTask; + }); + + // Act + httpContext.Request.Path = "/initial"; + await middleware.Invoke(httpContext); + httpContext.Request.Path = "/changed"; + await middleware.Invoke(httpContext); + + // Assert + matcher.Verify(); + } + [Fact] public async Task Invoke_OnException_ResetsEndpoint() {