From 4bed2e6f2b3e775ee58deb82ac584210c3e41ed6 Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Tue, 12 May 2015 16:06:21 -0700 Subject: [PATCH] [Fixes #2545] RedirectToRouteResult doesn't use RouteName property when calculating destination URL --- .../ActionResults/RedirectToRouteResult.cs | 2 +- .../RedirectToRouteResultTest.cs | 33 +++++++++++++++++++ .../LinkGenerationTests.cs | 11 ++++--- .../WebApiCompatShimActionResultTest.cs | 12 ++++--- .../Controllers/HomeController.cs | 5 +++ .../ActionResults/ActionResultController.cs | 5 +++ 6 files changed, 59 insertions(+), 9 deletions(-) diff --git a/src/Microsoft.AspNet.Mvc.Core/ActionResults/RedirectToRouteResult.cs b/src/Microsoft.AspNet.Mvc.Core/ActionResults/RedirectToRouteResult.cs index 08d29ea87c..a830428bfd 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ActionResults/RedirectToRouteResult.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ActionResults/RedirectToRouteResult.cs @@ -45,7 +45,7 @@ namespace Microsoft.AspNet.Mvc { var urlHelper = GetUrlHelper(context); - var destinationUrl = urlHelper.RouteUrl(RouteValues); + var destinationUrl = urlHelper.RouteUrl(RouteName, RouteValues); if (string.IsNullOrEmpty(destinationUrl)) { throw new InvalidOperationException(Resources.NoRoutesMatched); diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ActionResults/RedirectToRouteResultTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ActionResults/RedirectToRouteResultTest.cs index 8d04e96aff..6474f5c937 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ActionResults/RedirectToRouteResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ActionResults/RedirectToRouteResultTest.cs @@ -3,7 +3,9 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; using Microsoft.AspNet.Http; +using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Routing; using Microsoft.AspNet.Testing; using Moq; @@ -97,6 +99,37 @@ namespace Microsoft.AspNet.Mvc.Core tempData.Verify(t => t.Keep(), Times.Once()); } + [Fact] + public async Task ExecuteResultAsync_UsesRouteName_ToGenerateLocationHeader() + { + // Arrange + var routeName = "orders_api"; + var locationUrl = "/api/orders/10"; + var urlHelper = new Mock(); + urlHelper.Setup(uh => uh.RouteUrl(It.IsAny())) + .Returns(locationUrl) + .Verifiable(); + + var serviceProvider = new Mock(); + serviceProvider.Setup(sp => sp.GetService(typeof(IUrlHelper))) + .Returns(urlHelper.Object); + serviceProvider.Setup(sp => sp.GetService(typeof(ITempDataDictionary))) + .Returns(new Mock().Object); + var httpContext = new DefaultHttpContext(); + httpContext.RequestServices = serviceProvider.Object; + var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); + var result = new RedirectToRouteResult(routeName, new { id = 10 }); + + // Act + await result.ExecuteResultAsync(actionContext); + + // Assert + urlHelper.Verify(uh => uh.RouteUrl( + It.Is(routeContext => string.Equals(routeName, routeContext.RouteName)))); + Assert.True(httpContext.Response.Headers.ContainsKey("Location"), "Location header not found"); + Assert.Equal(locationUrl, httpContext.Response.Headers["Location"]); + } + public static IEnumerable RedirectToRouteData { get diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/LinkGenerationTests.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/LinkGenerationTests.cs index ce0e3abc9c..4582c4a497 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/LinkGenerationTests.cs +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/LinkGenerationTests.cs @@ -26,9 +26,12 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests private readonly Assembly _resourcesAssembly = typeof(LinkGenerationTests).GetTypeInfo().Assembly; [Theory] - [InlineData("http://pingüino/Home/RedirectToActionReturningTaskAction")] - [InlineData("http://pingüino/Home/RedirectToRouteActionAsMethodAction")] - public async Task GeneratedLinksWithActionResults_AreRelativeLinks_WhenSetOnLocationHeader(string url) + [InlineData("http://pingüino/Home/RedirectToActionReturningTaskAction", "/Home/ActionReturningTask")] + [InlineData("http://pingüino/Home/RedirectToRouteActionAsMethodAction", "/Home/ActionReturningTask")] + [InlineData("http://pingüino/Home/RedirectToRouteUsingRouteName", "/api/orders/10")] + public async Task GeneratedLinksWithActionResults_AreRelativeLinks_WhenSetOnLocationHeader( + string url, + string expected) { // Arrange var server = TestHelper.CreateServer(_app, SiteName, _configureServices); @@ -43,7 +46,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests // Assert Assert.Equal(HttpStatusCode.Redirect, response.StatusCode); - Assert.Equal("/Home/ActionReturningTask", response.Headers.Location.ToString()); + Assert.Equal(expected, response.Headers.Location.ToString()); } [Fact] diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/WebApiCompatShimActionResultTest.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/WebApiCompatShimActionResultTest.cs index bb95c9d2ca..4be9460258 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/WebApiCompatShimActionResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/WebApiCompatShimActionResultTest.cs @@ -327,19 +327,23 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests Assert.Equal("http://localhost/api/Users", response.Headers.Location.OriginalString); } - [Fact] - public async Task ApiController_RedirectUri() + [Theory] + [InlineData("http://localhost/api/Blog/ActionResult/GetRedirectUri", "api/Blog")] + [InlineData( + "http://localhost/api/Blog/ActionResult/GetRedirectUrlUsingRouteName", + "/api/Blog/BasicApi/WriteToHttpContext")] + public async Task ApiController_RedirectUri(string url, string expected) { // Arrange var server = TestHelper.CreateServer(_app, SiteName, _configureServices); var client = server.CreateClient(); // Act - var response = await client.GetAsync("http://localhost/api/Blog/ActionResult/GetRedirectUri"); + var response = await client.GetAsync(url); // Assert Assert.Equal(HttpStatusCode.Redirect, response.StatusCode); - Assert.Equal("api/Blog", response.Headers.Location.OriginalString); + Assert.Equal(expected, response.Headers.Location.OriginalString); } [Fact] diff --git a/test/WebSites/BasicWebSite/Controllers/HomeController.cs b/test/WebSites/BasicWebSite/Controllers/HomeController.cs index 71760d1a5c..a16e9fa641 100644 --- a/test/WebSites/BasicWebSite/Controllers/HomeController.cs +++ b/test/WebSites/BasicWebSite/Controllers/HomeController.cs @@ -37,6 +37,11 @@ namespace BasicWebSite.Controllers return RedirectToRoute("ActionAsMethod", new { action = "ActionReturningTask", controller = "Home" }); } + public IActionResult RedirectToRouteUsingRouteName() + { + return RedirectToRoute("OrdersApi", new { id = 10 }); + } + public IActionResult NoContentResult() { return new HttpStatusCodeResult(StatusCodes.Status204NoContent); diff --git a/test/WebSites/WebApiCompatShimWebSite/Controllers/ActionResults/ActionResultController.cs b/test/WebSites/WebApiCompatShimWebSite/Controllers/ActionResults/ActionResultController.cs index 1ddd7bcb6f..9dee6afe53 100644 --- a/test/WebSites/WebApiCompatShimWebSite/Controllers/ActionResults/ActionResultController.cs +++ b/test/WebSites/WebApiCompatShimWebSite/Controllers/ActionResults/ActionResultController.cs @@ -120,6 +120,11 @@ namespace WebApiCompatShimWebSite return Redirect(new Uri("api/Blog", UriKind.RelativeOrAbsolute)); } + public IActionResult GetRedirectUrlUsingRouteName() + { + return RedirectToRoute("named-action", new { controller = "BasicApi", action = "WriteToHttpContext" }); + } + public IActionResult GetResponseMessage() { var response = new HttpResponseMessage(HttpStatusCode.OK);