RedirectToPage from a form-action handler includes the formaction
Fixes #6104
This commit is contained in:
parent
106b34867d
commit
3474bdf776
|
|
@ -89,9 +89,9 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
}
|
}
|
||||||
|
|
||||||
var routeValues = new RouteValueDictionary(values);
|
var routeValues = new RouteValueDictionary(values);
|
||||||
|
var ambientValues = urlHelper.ActionContext.RouteData.Values;
|
||||||
if (pageName == null)
|
if (pageName == null)
|
||||||
{
|
{
|
||||||
var ambientValues = urlHelper.ActionContext.RouteData.Values;
|
|
||||||
if (!routeValues.ContainsKey("page") &&
|
if (!routeValues.ContainsKey("page") &&
|
||||||
ambientValues.TryGetValue("page", out var value))
|
ambientValues.TryGetValue("page", out var value))
|
||||||
{
|
{
|
||||||
|
|
@ -103,6 +103,13 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
routeValues["page"] = pageName;
|
routeValues["page"] = pageName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!routeValues.ContainsKey("formaction") &&
|
||||||
|
ambientValues.TryGetValue("formaction", out var formaction))
|
||||||
|
{
|
||||||
|
// Clear out formaction unless it's explicitly specified in the routeValues.
|
||||||
|
routeValues["formaction"] = null;
|
||||||
|
}
|
||||||
|
|
||||||
return urlHelper.RouteUrl(
|
return urlHelper.RouteUrl(
|
||||||
routeName: null,
|
routeName: null,
|
||||||
values: routeValues,
|
values: routeValues,
|
||||||
|
|
|
||||||
|
|
@ -763,6 +763,34 @@ Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary`1[AspNetCore._InjectedP
|
||||||
Assert.Equal(expected, response.Headers.Location.ToString());
|
Assert.Equal(expected, response.Headers.Location.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task RedirectDoesNotIncludeFormActionByDefault()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expected = "/Pages/Redirects/RedirectFromFormActionHandler";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await Client.GetAsync("/Pages/Redirects/RedirectFromFormActionHandler/RedirectToPage/10");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
|
||||||
|
Assert.Equal(expected, response.Headers.Location.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task RedirectToOtherHandlersWorks()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expected = "/Pages/Redirects/RedirectFromFormActionHandler/RedirectToPage/11";
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await Client.GetAsync("/Pages/Redirects/RedirectFromFormActionHandler/RedirectToAnotherHandler/11");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
|
||||||
|
Assert.Equal(expected, response.Headers.Location.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
private async Task AddAntiforgeryHeaders(HttpRequestMessage request)
|
private async Task AddAntiforgeryHeaders(HttpRequestMessage request)
|
||||||
{
|
{
|
||||||
var getResponse = await Client.GetAsync(request.RequestUri);
|
var getResponse = await Client.GetAsync(request.RequestUri);
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
|
||||||
{
|
{
|
||||||
RouteData = routeData,
|
RouteData = routeData,
|
||||||
};
|
};
|
||||||
var urlHelper = new Mock<IUrlHelper>();
|
var urlHelper = CreateUrlHelper(actionContext);
|
||||||
urlHelper.SetupGet(h => h.ActionContext)
|
|
||||||
.Returns(actionContext);
|
|
||||||
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
|
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
|
||||||
.Callback((UrlRouteContext context) => actual = context);
|
.Callback((UrlRouteContext context) => actual = context);
|
||||||
|
|
||||||
|
|
@ -77,7 +75,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
UrlRouteContext actual = null;
|
UrlRouteContext actual = null;
|
||||||
var urlHelper = new Mock<IUrlHelper>();
|
var urlHelper = CreateUrlHelper();
|
||||||
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
|
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
|
||||||
.Callback((UrlRouteContext context) => actual = context);
|
.Callback((UrlRouteContext context) => actual = context);
|
||||||
|
|
||||||
|
|
@ -109,7 +107,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
UrlRouteContext actual = null;
|
UrlRouteContext actual = null;
|
||||||
var urlHelper = new Mock<IUrlHelper>();
|
var urlHelper = CreateUrlHelper();
|
||||||
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
|
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
|
||||||
.Callback((UrlRouteContext context) => actual = context);
|
.Callback((UrlRouteContext context) => actual = context);
|
||||||
|
|
||||||
|
|
@ -141,7 +139,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
UrlRouteContext actual = null;
|
UrlRouteContext actual = null;
|
||||||
var urlHelper = new Mock<IUrlHelper>();
|
var urlHelper = CreateUrlHelper();
|
||||||
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
|
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
|
||||||
.Callback((UrlRouteContext context) => actual = context);
|
.Callback((UrlRouteContext context) => actual = context);
|
||||||
|
|
||||||
|
|
@ -173,7 +171,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
UrlRouteContext actual = null;
|
UrlRouteContext actual = null;
|
||||||
var urlHelper = new Mock<IUrlHelper>();
|
var urlHelper = CreateUrlHelper();
|
||||||
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
|
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
|
||||||
.Callback((UrlRouteContext context) => actual = context);
|
.Callback((UrlRouteContext context) => actual = context);
|
||||||
|
|
||||||
|
|
@ -217,9 +215,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
|
||||||
RouteData = routeData,
|
RouteData = routeData,
|
||||||
};
|
};
|
||||||
|
|
||||||
var urlHelper = new Mock<IUrlHelper>();
|
var urlHelper = CreateUrlHelper(actionContext);
|
||||||
urlHelper.SetupGet(p => p.ActionContext)
|
|
||||||
.Returns(actionContext);
|
|
||||||
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
|
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
|
||||||
.Callback((UrlRouteContext context) => actual = context);
|
.Callback((UrlRouteContext context) => actual = context);
|
||||||
|
|
||||||
|
|
@ -246,5 +242,112 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
|
||||||
Assert.Equal("mytesthost", actual.Host);
|
Assert.Equal("mytesthost", actual.Host);
|
||||||
Assert.Equal("#toc", actual.Fragment);
|
Assert.Equal("#toc", actual.Fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Page_SetsFormActionToNull_IfValueIsNotSpecifiedInRouteValues()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
UrlRouteContext actual = null;
|
||||||
|
var routeData = new RouteData
|
||||||
|
{
|
||||||
|
Values =
|
||||||
|
{
|
||||||
|
{ "page", "ambient-page" },
|
||||||
|
{ "formaction", "ambient-formaction" },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var actionContext = new ActionContext
|
||||||
|
{
|
||||||
|
RouteData = routeData,
|
||||||
|
};
|
||||||
|
|
||||||
|
var urlHelper = CreateUrlHelper(actionContext);
|
||||||
|
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
|
||||||
|
.Callback((UrlRouteContext context) => actual = context);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
string page = null;
|
||||||
|
urlHelper.Object.Page(page, new { id = 13 }, "https", "mytesthost", "#toc");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
urlHelper.Verify();
|
||||||
|
Assert.NotNull(actual);
|
||||||
|
Assert.Null(actual.RouteName);
|
||||||
|
Assert.Collection(Assert.IsType<RouteValueDictionary>(actual.Values),
|
||||||
|
value =>
|
||||||
|
{
|
||||||
|
Assert.Equal("id", value.Key);
|
||||||
|
Assert.Equal(13, value.Value);
|
||||||
|
},
|
||||||
|
value =>
|
||||||
|
{
|
||||||
|
Assert.Equal("page", value.Key);
|
||||||
|
Assert.Equal("ambient-page", value.Value);
|
||||||
|
},
|
||||||
|
value =>
|
||||||
|
{
|
||||||
|
Assert.Equal("formaction", value.Key);
|
||||||
|
Assert.Null(value.Value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Page_UsesExplicitlySpecifiedFormActionValue()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
UrlRouteContext actual = null;
|
||||||
|
var routeData = new RouteData
|
||||||
|
{
|
||||||
|
Values =
|
||||||
|
{
|
||||||
|
{ "page", "ambient-page" },
|
||||||
|
{ "formaction", "ambient-formaction" },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var actionContext = new ActionContext
|
||||||
|
{
|
||||||
|
RouteData = routeData,
|
||||||
|
};
|
||||||
|
|
||||||
|
var urlHelper = CreateUrlHelper(actionContext);
|
||||||
|
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
|
||||||
|
.Callback((UrlRouteContext context) => actual = context);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
string page = null;
|
||||||
|
urlHelper.Object.Page(page, new { formaction = "exact-formaction" }, "https", "mytesthost", "#toc");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
urlHelper.Verify();
|
||||||
|
Assert.NotNull(actual);
|
||||||
|
Assert.Null(actual.RouteName);
|
||||||
|
Assert.Collection(Assert.IsType<RouteValueDictionary>(actual.Values),
|
||||||
|
value =>
|
||||||
|
{
|
||||||
|
Assert.Equal("formaction", value.Key);
|
||||||
|
Assert.Equal("exact-formaction", value.Value);
|
||||||
|
},
|
||||||
|
value =>
|
||||||
|
{
|
||||||
|
Assert.Equal("page", value.Key);
|
||||||
|
Assert.Equal("ambient-page", value.Value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Mock<IUrlHelper> CreateUrlHelper(ActionContext context = null)
|
||||||
|
{
|
||||||
|
if (context == null)
|
||||||
|
{
|
||||||
|
context = new ActionContext
|
||||||
|
{
|
||||||
|
RouteData = new RouteData(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var urlHelper = new Mock<IUrlHelper>();
|
||||||
|
urlHelper.SetupGet(h => h.ActionContext)
|
||||||
|
.Returns(context);
|
||||||
|
return urlHelper;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
|
||||||
|
|
||||||
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
|
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
|
||||||
|
|
||||||
var urlHelper = GetUrlHelper(returnValue: null);
|
var urlHelper = GetUrlHelper(actionContext, returnValue: null);
|
||||||
var result = new RedirectToPageResult("some-page", new Dictionary<string, object>())
|
var result = new RedirectToPageResult("some-page", new Dictionary<string, object>())
|
||||||
{
|
{
|
||||||
UrlHelper = urlHelper,
|
UrlHelper = urlHelper,
|
||||||
|
|
@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
|
||||||
new RouteData(),
|
new RouteData(),
|
||||||
new ActionDescriptor());
|
new ActionDescriptor());
|
||||||
|
|
||||||
var urlHelper = GetUrlHelper(expectedUrl);
|
var urlHelper = GetUrlHelper(actionContext, expectedUrl);
|
||||||
var result = new RedirectToPageResult("MyPage", new { id = 10, test = "value" }, permanentRedirect)
|
var result = new RedirectToPageResult("MyPage", new { id = 10, test = "value" }, permanentRedirect)
|
||||||
{
|
{
|
||||||
UrlHelper = urlHelper,
|
UrlHelper = urlHelper,
|
||||||
|
|
@ -89,10 +89,12 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
|
||||||
var pageContext = new PageContext
|
var pageContext = new PageContext
|
||||||
{
|
{
|
||||||
HttpContext = httpContext,
|
HttpContext = httpContext,
|
||||||
|
RouteData = new RouteData(),
|
||||||
};
|
};
|
||||||
|
|
||||||
UrlRouteContext context = null;
|
UrlRouteContext context = null;
|
||||||
var urlHelper = new Mock<IUrlHelper>();
|
var urlHelper = new Mock<IUrlHelper>();
|
||||||
|
urlHelper.SetupGet(h => h.ActionContext).Returns(pageContext);
|
||||||
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
|
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
|
||||||
.Callback((UrlRouteContext c) => context = c)
|
.Callback((UrlRouteContext c) => context = c)
|
||||||
.Returns("some-value");
|
.Returns("some-value");
|
||||||
|
|
@ -174,6 +176,62 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task RedirectToPage_DoesNotUseAmbientFormAction()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expected = "path/to/this-page";
|
||||||
|
var httpContext = new Mock<HttpContext>();
|
||||||
|
var httpResponse = new Mock<HttpResponse>();
|
||||||
|
httpContext.SetupGet(c => c.Response)
|
||||||
|
.Returns(httpResponse.Object);
|
||||||
|
httpContext.SetupGet(c => c.RequestServices)
|
||||||
|
.Returns(CreateServices());
|
||||||
|
var routeData = new RouteData
|
||||||
|
{
|
||||||
|
Values =
|
||||||
|
{
|
||||||
|
["page"] = expected,
|
||||||
|
["formaction"] = "delete",
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var actionContext = new ActionContext(
|
||||||
|
httpContext.Object,
|
||||||
|
routeData,
|
||||||
|
new ActionDescriptor());
|
||||||
|
|
||||||
|
UrlRouteContext context = null;
|
||||||
|
var urlHelper = new Mock<IUrlHelper>();
|
||||||
|
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
|
||||||
|
.Callback((UrlRouteContext c) => context = c)
|
||||||
|
.Returns("some-value");
|
||||||
|
urlHelper.SetupGet(h => h.ActionContext)
|
||||||
|
.Returns(actionContext);
|
||||||
|
var pageName = (string)null;
|
||||||
|
var result = new RedirectToPageResult(pageName)
|
||||||
|
{
|
||||||
|
UrlHelper = urlHelper.Object,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await result.ExecuteResultAsync(actionContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.NotNull(context);
|
||||||
|
Assert.Collection(Assert.IsType<RouteValueDictionary>(context.Values),
|
||||||
|
value =>
|
||||||
|
{
|
||||||
|
Assert.Equal("page", value.Key);
|
||||||
|
Assert.Equal(expected, value.Value);
|
||||||
|
},
|
||||||
|
value =>
|
||||||
|
{
|
||||||
|
Assert.Equal("formaction", value.Key);
|
||||||
|
Assert.Null(value.Value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private static IServiceProvider CreateServices(IUrlHelperFactory factory = null)
|
private static IServiceProvider CreateServices(IUrlHelperFactory factory = null)
|
||||||
{
|
{
|
||||||
var services = new ServiceCollection();
|
var services = new ServiceCollection();
|
||||||
|
|
@ -192,9 +250,10 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
|
||||||
return services.BuildServiceProvider();
|
return services.BuildServiceProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IUrlHelper GetUrlHelper(string returnValue)
|
private static IUrlHelper GetUrlHelper(ActionContext context, string returnValue)
|
||||||
{
|
{
|
||||||
var urlHelper = new Mock<IUrlHelper>();
|
var urlHelper = new Mock<IUrlHelper>();
|
||||||
|
urlHelper.SetupGet(h => h.ActionContext).Returns(context);
|
||||||
urlHelper.Setup(o => o.RouteUrl(It.IsAny<UrlRouteContext>())).Returns(returnValue);
|
urlHelper.Setup(o => o.RouteUrl(It.IsAny<UrlRouteContext>())).Returns(returnValue);
|
||||||
return urlHelper.Object;
|
return urlHelper.Object;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
@page "{formaction?}/{id:int?}"
|
||||||
|
@functions
|
||||||
|
{
|
||||||
|
public IActionResult OnGetRedirectToPage(int id)
|
||||||
|
{
|
||||||
|
return RedirectToPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IActionResult OnGetRedirectToAnotherHandler(int id)
|
||||||
|
{
|
||||||
|
return RedirectToPage(new { formaction = "RedirectToPage", id = id });
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue