From 6f305373cadf769a2ff9aab75932cf92ce8cc3fc Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Tue, 16 Apr 2019 09:58:13 -0700 Subject: [PATCH] Allow fallback to controller to use MatcherPolicy --- .../DynamicControllerEndpointMatcherPolicy.cs | 17 +++++++++++++---- .../DynamicPageEndpointMatcherPolicy.cs | 4 ++++ .../Mvc.FunctionalTests/RoutingFallbackTest.cs | 16 ++++++++++++++++ .../Areas/Admin/FallbackController.cs | 6 ++++++ 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/Mvc/Mvc.Core/src/Routing/DynamicControllerEndpointMatcherPolicy.cs b/src/Mvc/Mvc.Core/src/Routing/DynamicControllerEndpointMatcherPolicy.cs index 798a13f109..0dcc828c5f 100644 --- a/src/Mvc/Mvc.Core/src/Routing/DynamicControllerEndpointMatcherPolicy.cs +++ b/src/Mvc/Mvc.Core/src/Routing/DynamicControllerEndpointMatcherPolicy.cs @@ -14,15 +14,22 @@ namespace Microsoft.AspNetCore.Mvc.Routing internal class DynamicControllerEndpointMatcherPolicy : MatcherPolicy, IEndpointSelectorPolicy { private readonly DynamicControllerEndpointSelector _selector; + private readonly EndpointMetadataComparer _comparer; - public DynamicControllerEndpointMatcherPolicy(DynamicControllerEndpointSelector selector) + public DynamicControllerEndpointMatcherPolicy(DynamicControllerEndpointSelector selector, EndpointMetadataComparer comparer) { if (selector == null) { throw new ArgumentNullException(nameof(selector)); } + if (comparer == null) + { + throw new ArgumentNullException(nameof(comparer)); + } + _selector = selector; + _comparer = comparer; } public override int Order => int.MinValue + 100; @@ -99,8 +106,6 @@ namespace Microsoft.AspNetCore.Mvc.Routing "{ " + string.Join(", ", metadata.Values.Select(kvp => $"{kvp.Key}: {kvp.Value}")) + " }."); } - var replacement = endpoints[0]; - // We need to provide the route values associated with this endpoint, so that features // like URL generation work. var values = new RouteValueDictionary(metadata.Values); @@ -111,7 +116,11 @@ namespace Microsoft.AspNetCore.Mvc.Routing values.TryAdd(kvp.Key, kvp.Value); } - candidates.ReplaceEndpoint(i, replacement, values); + // Update the route values + candidates.ReplaceEndpoint(i, endpoint, values); + + // Expand the list of endpoints + candidates.ExpandEndpoint(i, endpoints, _comparer); } return Task.CompletedTask; diff --git a/src/Mvc/Mvc.RazorPages/src/Infrastructure/DynamicPageEndpointMatcherPolicy.cs b/src/Mvc/Mvc.RazorPages/src/Infrastructure/DynamicPageEndpointMatcherPolicy.cs index cf41aac9fd..f7321e79b7 100644 --- a/src/Mvc/Mvc.RazorPages/src/Infrastructure/DynamicPageEndpointMatcherPolicy.cs +++ b/src/Mvc/Mvc.RazorPages/src/Infrastructure/DynamicPageEndpointMatcherPolicy.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; @@ -106,6 +107,9 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure "{ " + string.Join(", ", metadata.Values.Select(kvp => $"{kvp.Key}: {kvp.Value}")) + " }."); } + // It should not be possible to have more than one result for pages. + Debug.Assert(endpoints.Count == 1); + var compiled = await _loader.LoadAsync(endpoints[0].Metadata.GetMetadata()); var replacement = compiled.Endpoint; diff --git a/src/Mvc/test/Mvc.FunctionalTests/RoutingFallbackTest.cs b/src/Mvc/test/Mvc.FunctionalTests/RoutingFallbackTest.cs index ed23c1fe02..eb41d3b7f4 100644 --- a/src/Mvc/test/Mvc.FunctionalTests/RoutingFallbackTest.cs +++ b/src/Mvc/test/Mvc.FunctionalTests/RoutingFallbackTest.cs @@ -69,6 +69,22 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests Assert.Equal("Hello from fallback controller: /Admin/Fallback", content); } + [Fact] + public async Task Fallback_CanFallbackToControllerInAreaPost() + { + // Arrange + var url = "http://localhost/Admin/Foo"; + var request = new HttpRequestMessage(HttpMethod.Post, url); + + // Act + var response = await Client.SendAsync(request); + var content = await response.Content.ReadAsStringAsync(); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal("Hello from fallback controller POST: /Admin/Fallback", content); + } + [Fact] public async Task Fallback_CanFallbackToPage() { diff --git a/src/Mvc/test/WebSites/RoutingWebSite/Areas/Admin/FallbackController.cs b/src/Mvc/test/WebSites/RoutingWebSite/Areas/Admin/FallbackController.cs index a15564d2b7..64d0cd7875 100644 --- a/src/Mvc/test/WebSites/RoutingWebSite/Areas/Admin/FallbackController.cs +++ b/src/Mvc/test/WebSites/RoutingWebSite/Areas/Admin/FallbackController.cs @@ -12,5 +12,11 @@ namespace RoutingWebSite.Areas.Admin { return Content("Hello from fallback controller: " + Url.Action()); } + + [HttpPost] + public ActionResult Index(int x) + { + return Content("Hello from fallback controller POST: " + Url.Action()); + } } }