diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/DefaultPageHandlerMethodSelector.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/DefaultPageHandlerMethodSelector.cs index 725bdee934..3ef2339520 100644 --- a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/DefaultPageHandlerMethodSelector.cs +++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/DefaultPageHandlerMethodSelector.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.Primitives; namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure { @@ -65,6 +66,13 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure List handlersToConsider = null; var formAction = Convert.ToString(context.RouteData.Values[FormAction]); + + if (string.IsNullOrEmpty(formAction) && + context.HttpContext.Request.Query.TryGetValue(FormAction, out StringValues queryValues)) + { + formAction = queryValues[0]; + } + for (var i = 0; i < handlers.Count; i++) { var handler = handlers[i]; diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesTest.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesTest.cs index 0def6c5d57..bd705a348a 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesTest.cs @@ -20,6 +20,26 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests public HttpClient Client { get; } + [Fact] + public async Task Page_Handler_FormActionFromQueryString() + { + // Arrange & Act + var content = await Client.GetStringAsync("http://localhost/HandlerTestPage?formaction=Customer"); + + // Assert + Assert.StartsWith("Method: OnGetCustomer", content.Trim()); + } + + [Fact] + public async Task Page_Handler_FormActionRouteDataChosenOverQueryString() + { + // Arrange & Act + var content = await Client.GetStringAsync("http://localhost/HandlerTestPage/Customer?formaction=ViewCustomer"); + + // Assert + Assert.StartsWith("Method: OnGetCustomer", content.Trim()); + } + [Fact] public async Task Page_Handler_FormAction() { diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/DefaultPageHandlerMethodSelectorTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/DefaultPageHandlerMethodSelectorTest.cs index dd739f0170..d5536d1209 100644 --- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/DefaultPageHandlerMethodSelectorTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/DefaultPageHandlerMethodSelectorTest.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Reflection; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure; using Microsoft.AspNetCore.Routing; @@ -234,6 +233,147 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal Assert.Same(descriptor1, actual); } + [Fact] + public void Select_FormActionFromQueryString() + { + // Arrange + var descriptor1 = new HandlerMethodDescriptor + { + HttpMethod = "POST", + FormAction = new StringSegment("Add"), + }; + + var descriptor2 = new HandlerMethodDescriptor + { + HttpMethod = "POST", + FormAction = new StringSegment("Delete"), + }; + + var pageContext = new PageContext + { + ActionDescriptor = new CompiledPageActionDescriptor + { + HandlerMethods = + { + descriptor1, + descriptor2, + }, + }, + RouteData = new RouteData(), + HttpContext = new DefaultHttpContext + { + Request = + { + Method = "Post", + QueryString = new QueryString("?formaction=Delete"), + }, + }, + }; + var selector = new DefaultPageHandlerMethodSelector(); + + // Act + var actual = selector.Select(pageContext); + + // Assert + Assert.Same(descriptor2, actual); + } + + [Fact] + public void Select_FormActionConsidersRouteDataFirst() + { + // Arrange + var descriptor1 = new HandlerMethodDescriptor + { + HttpMethod = "POST", + FormAction = new StringSegment("Add"), + }; + + var descriptor2 = new HandlerMethodDescriptor + { + HttpMethod = "POST", + FormAction = new StringSegment("Delete"), + }; + + var pageContext = new PageContext + { + ActionDescriptor = new CompiledPageActionDescriptor + { + HandlerMethods = + { + descriptor1, + descriptor2, + }, + }, + RouteData = new RouteData + { + Values = + { + { "formaction", "Add" } + } + }, + HttpContext = new DefaultHttpContext + { + Request = + { + Method = "Post", + QueryString = new QueryString("?formaction=Delete"), + }, + }, + }; + var selector = new DefaultPageHandlerMethodSelector(); + + // Act + var actual = selector.Select(pageContext); + + // Assert + Assert.Same(descriptor1, actual); + } + + [Fact] + public void Select_FormActionMultipleTimesInQueryString_UsesFirst() + { + // Arrange + var descriptor1 = new HandlerMethodDescriptor + { + HttpMethod = "POST", + FormAction = new StringSegment("Add"), + }; + + var descriptor2 = new HandlerMethodDescriptor + { + HttpMethod = "POST", + FormAction = new StringSegment("Delete"), + }; + + var pageContext = new PageContext + { + ActionDescriptor = new CompiledPageActionDescriptor + { + HandlerMethods = + { + descriptor1, + descriptor2, + }, + }, + RouteData = new RouteData(), + HttpContext = new DefaultHttpContext + { + Request = + { + Method = "Post", + QueryString = new QueryString("?formaction=Delete&formaction=Add"), + }, + }, + }; + var selector = new DefaultPageHandlerMethodSelector(); + + // Act + var actual = selector.Select(pageContext); + + // Assert + Assert.Same(descriptor2, actual); + } + [Fact] public void Select_ReturnsHandlerWithMatchingHttpMethodWithoutAFormAction() {