From 497a38035d98fa017c0db5468c2e19a4763f8040 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Sun, 15 Jul 2018 11:50:55 +1200 Subject: [PATCH] Add application startup check that dispatcher is added to request pipeline (#614) --- .../DispatcherApplicationBuilderExtensions.cs | 12 ++++++++++ .../EndpointMiddleware.cs | 5 +++- ...atcherApplicationBuilderExtensionsTest.cs} | 23 +++++++++++++++++-- .../EndpointMiddlewareTest.cs | 5 +++- 4 files changed, 41 insertions(+), 4 deletions(-) rename test/Microsoft.AspNetCore.Routing.Tests/{DispatcherApplicationBuilderExtensions.cs => DispatcherApplicationBuilderExtensionsTest.cs} (77%) diff --git a/src/Microsoft.AspNetCore.Routing/Builder/DispatcherApplicationBuilderExtensions.cs b/src/Microsoft.AspNetCore.Routing/Builder/DispatcherApplicationBuilderExtensions.cs index df0528799e..90ac0ce3fb 100644 --- a/src/Microsoft.AspNetCore.Routing/Builder/DispatcherApplicationBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Routing/Builder/DispatcherApplicationBuilderExtensions.cs @@ -10,10 +10,14 @@ namespace Microsoft.AspNetCore.Builder { public static class DispatcherApplicationBuilderExtensions { + private const string DispatcherRegisteredKey = "__DispatcherMiddlewareRegistered"; + public static IApplicationBuilder UseDispatcher(this IApplicationBuilder builder) { VerifyDispatcherIsRegistered(builder); + builder.Properties[DispatcherRegisteredKey] = true; + return builder.UseMiddleware(); } @@ -21,6 +25,14 @@ namespace Microsoft.AspNetCore.Builder { VerifyDispatcherIsRegistered(builder); + if (!builder.Properties.TryGetValue(DispatcherRegisteredKey, out _)) + { + var message = $"{nameof(DispatcherMiddleware)} must be added to the request execution pipeline before {nameof(EndpointMiddleware)}. " + + $"Please add {nameof(DispatcherMiddleware)} by calling '{nameof(IApplicationBuilder)}.{nameof(UseDispatcher)}' inside the call to 'Configure(...)' in the application startup code."; + + throw new InvalidOperationException(message); + } + return builder.UseMiddleware(); } diff --git a/src/Microsoft.AspNetCore.Routing/EndpointMiddleware.cs b/src/Microsoft.AspNetCore.Routing/EndpointMiddleware.cs index d7c90728dc..36e888ccb1 100644 --- a/src/Microsoft.AspNetCore.Routing/EndpointMiddleware.cs +++ b/src/Microsoft.AspNetCore.Routing/EndpointMiddleware.cs @@ -34,7 +34,10 @@ namespace Microsoft.AspNetCore.Routing var feature = httpContext.Features.Get(); if (feature == null) { - throw new InvalidOperationException("Unable to execute an endpoint because the dispatcher was not run. Ensure dispatcher middleware is registered."); + var message = $"Unable to execute an endpoint because the {nameof(DispatcherMiddleware)} was not run for this request. " + + $"Ensure {nameof(DispatcherMiddleware)} is added to the request execution pipeline before {nameof(EndpointMiddleware)} in application startup code."; + + throw new InvalidOperationException(message); } if (feature.Invoker != null) diff --git a/test/Microsoft.AspNetCore.Routing.Tests/DispatcherApplicationBuilderExtensions.cs b/test/Microsoft.AspNetCore.Routing.Tests/DispatcherApplicationBuilderExtensionsTest.cs similarity index 77% rename from test/Microsoft.AspNetCore.Routing.Tests/DispatcherApplicationBuilderExtensions.cs rename to test/Microsoft.AspNetCore.Routing.Tests/DispatcherApplicationBuilderExtensionsTest.cs index 6398227db1..a748f57557 100644 --- a/test/Microsoft.AspNetCore.Routing.Tests/DispatcherApplicationBuilderExtensions.cs +++ b/test/Microsoft.AspNetCore.Routing.Tests/DispatcherApplicationBuilderExtensionsTest.cs @@ -12,7 +12,7 @@ using Xunit; namespace Microsoft.AspNetCore.Builder { - public class DispatcherApplicationBuilderExtensions + public class DispatcherApplicationBuilderExtensionsTest { [Fact] public void UseDispatcher_ServicesNotRegistered_Throws() @@ -69,7 +69,26 @@ namespace Microsoft.AspNetCore.Builder } [Fact] - public async Task UseEndpoint_ServicesRegistered_SetsFeature() + public void UseEndpoint_ServicesRegisteredAndNoDispatcherRegistered_Throws() + { + // Arrange + var services = CreateServices(); + + var app = new ApplicationBuilder(services); + + // Act + var ex = Assert.Throws(() => app.UseEndpoint()); + + // Assert + Assert.Equal( + "DispatcherMiddleware must be added to the request execution pipeline before EndpointMiddleware. " + + "Please add DispatcherMiddleware by calling 'IApplicationBuilder.UseDispatcher' " + + "inside the call to 'Configure(...)' in the application startup code.", + ex.Message); + } + + [Fact] + public async Task UseEndpoint_ServicesRegisteredAndDispatcherRegistered_SetsFeature() { // Arrange var services = CreateServices(); diff --git a/test/Microsoft.AspNetCore.Routing.Tests/EndpointMiddlewareTest.cs b/test/Microsoft.AspNetCore.Routing.Tests/EndpointMiddlewareTest.cs index ff968fb7be..1a2829a42f 100644 --- a/test/Microsoft.AspNetCore.Routing.Tests/EndpointMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.Routing.Tests/EndpointMiddlewareTest.cs @@ -34,7 +34,10 @@ namespace Microsoft.AspNetCore.Routing // Assert var ex = await Assert.ThrowsAsync(async () => await invokeTask); - Assert.Equal("Unable to execute an endpoint because the dispatcher was not run. Ensure dispatcher middleware is registered.", ex.Message); + Assert.Equal( + "Unable to execute an endpoint because the DispatcherMiddleware was not run for this request. " + + "Ensure DispatcherMiddleware is added to the request execution pipeline before EndpointMiddleware in application startup code.", + ex.Message); } private class ServiceProvider : IServiceProvider