From 90395c933dee94859d6cf551d5073a8a0ee2413b Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Fri, 20 Jul 2018 18:23:14 +1200 Subject: [PATCH] Implement IRoutingFeature on EndpointFeature for back-compat (#641) --- .../RouteData.cs | 16 +++++++++- .../DispatcherMiddleware.cs | 3 ++ .../EndpointFeature.cs | 31 +++++++++++++++++-- .../DispatcherMiddlewareTest.cs | 24 ++++++++++++++ .../TestObjects/TestMatcher.cs | 1 + 5 files changed, 72 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.AspNetCore.Routing.Abstractions/RouteData.cs b/src/Microsoft.AspNetCore.Routing.Abstractions/RouteData.cs index 0ece2b91de..e0628dc1bb 100644 --- a/src/Microsoft.AspNetCore.Routing.Abstractions/RouteData.cs +++ b/src/Microsoft.AspNetCore.Routing.Abstractions/RouteData.cs @@ -51,6 +51,20 @@ namespace Microsoft.AspNetCore.Routing } } + /// + /// Creates a new instance with the specified values. + /// + /// The values. + public RouteData(RouteValueDictionary values) + { + if (values == null) + { + throw new ArgumentNullException(nameof(values)); + } + + _values = values; + } + /// /// Gets the data tokens produced by routes on the current routing path. /// @@ -84,7 +98,7 @@ namespace Microsoft.AspNetCore.Routing } /// - /// Gets the set of values produced by routes on the current routing path. + /// Gets the values produced by routes on the current routing path. /// public RouteValueDictionary Values { diff --git a/src/Microsoft.AspNetCore.Routing/DispatcherMiddleware.cs b/src/Microsoft.AspNetCore.Routing/DispatcherMiddleware.cs index cccebfe7b1..6dd9cbed16 100644 --- a/src/Microsoft.AspNetCore.Routing/DispatcherMiddleware.cs +++ b/src/Microsoft.AspNetCore.Routing/DispatcherMiddleware.cs @@ -57,6 +57,9 @@ namespace Microsoft.AspNetCore.Routing var feature = new EndpointFeature(); httpContext.Features.Set(feature); + // Back compat support for users of IRoutingFeature + httpContext.Features.Set(feature); + // There's an inherent race condition between waiting for init and accessing the matcher // this is OK because once `_matcher` is initialized, it will not be set to null again. var matcher = await InitializeAsync(); diff --git a/src/Microsoft.AspNetCore.Routing/EndpointFeature.cs b/src/Microsoft.AspNetCore.Routing/EndpointFeature.cs index 62d943ca84..99e5709867 100644 --- a/src/Microsoft.AspNetCore.Routing/EndpointFeature.cs +++ b/src/Microsoft.AspNetCore.Routing/EndpointFeature.cs @@ -6,12 +6,39 @@ using Microsoft.AspNetCore.Http; namespace Microsoft.AspNetCore.Routing { - public sealed class EndpointFeature : IEndpointFeature + public sealed class EndpointFeature : IEndpointFeature, IRoutingFeature { + private RouteData _routeData; + private RouteValueDictionary _values; + public Endpoint Endpoint { get; set; } public Func Invoker { get; set; } - public RouteValueDictionary Values { get; set; } + public RouteValueDictionary Values + { + get => _values; + set + { + _values = value; + + // RouteData will be created next get with new Values + _routeData = null; + } + } + + RouteData IRoutingFeature.RouteData + { + get + { + if (_routeData == null) + { + _routeData = new RouteData(_values); + } + + return _routeData; + } + set => throw new NotSupportedException(); + } } } diff --git a/test/Microsoft.AspNetCore.Routing.Tests/DispatcherMiddlewareTest.cs b/test/Microsoft.AspNetCore.Routing.Tests/DispatcherMiddlewareTest.cs index 4f5b72de8d..26fb753c38 100644 --- a/test/Microsoft.AspNetCore.Routing.Tests/DispatcherMiddlewareTest.cs +++ b/test/Microsoft.AspNetCore.Routing.Tests/DispatcherMiddlewareTest.cs @@ -58,6 +58,30 @@ namespace Microsoft.AspNetCore.Routing Assert.Equal(expectedMessage, write.State?.ToString()); } + [Fact] + public async Task Invoke_BackCompatGetRouteValue_ValueUsedFromEndpointFeature() + { + // Arrange + var httpContext = new DefaultHttpContext(); + httpContext.RequestServices = new TestServiceProvider(); + + var middleware = CreateMiddleware(); + + // Act + await middleware.Invoke(httpContext); + var routeData = httpContext.GetRouteData(); + var routeValue = httpContext.GetRouteValue("controller"); + var endpointFeature = httpContext.Features.Get(); + + // Assert + Assert.NotNull(routeData); + Assert.Equal("Home", (string)routeValue); + + // changing route data value is reflected in endpoint feature values + routeData.Values["testKey"] = "testValue"; + Assert.Equal("testValue", endpointFeature.Values["testKey"]); + } + private DispatcherMiddleware CreateMiddleware(Logger logger = null) { RequestDelegate next = (c) => Task.FromResult(null); diff --git a/test/Microsoft.AspNetCore.Routing.Tests/TestObjects/TestMatcher.cs b/test/Microsoft.AspNetCore.Routing.Tests/TestObjects/TestMatcher.cs index 58b8f37840..4994cdd008 100644 --- a/test/Microsoft.AspNetCore.Routing.Tests/TestObjects/TestMatcher.cs +++ b/test/Microsoft.AspNetCore.Routing.Tests/TestObjects/TestMatcher.cs @@ -20,6 +20,7 @@ namespace Microsoft.AspNetCore.Routing.TestObjects { if (_isHandled) { + feature.Values = new RouteValueDictionary(new { controller = "Home", action = "Index" }); feature.Endpoint = new TestEndpoint(EndpointMetadataCollection.Empty, "Test endpoint"); }