[Fixes #6117] Added RedirectToPage overloads to Controller

This commit is contained in:
Ajay Bhargav Baaskaran 2017-04-20 17:29:13 -07:00
parent 83faaebdb6
commit 8eac7c2d6c
20 changed files with 725 additions and 549 deletions

View File

@ -943,6 +943,148 @@ namespace Microsoft.AspNetCore.Mvc
}; };
} }
/// <summary>
/// Redirects (<see cref="StatusCodes.Status302Found"/>) to the specified <paramref name="pageName"/>.
/// </summary>
/// <param name="pageName">The name of the page.</param>
/// <returns>The <see cref="RedirectToPageResult"/>.</returns>
[NonAction]
public virtual RedirectToPageResult RedirectToPage(string pageName)
=> RedirectToPage(pageName, routeValues: null);
/// <summary>
/// Redirects (<see cref="StatusCodes.Status302Found"/>) to the specified <paramref name="pageName"/>
/// using the specified <paramref name="routeValues"/>.
/// </summary>
/// <param name="pageName">The name of the page.</param>
/// <param name="routeValues">The parameters for a route.</param>
/// <returns>The <see cref="RedirectToPageResult"/>.</returns>
[NonAction]
public virtual RedirectToPageResult RedirectToPage(string pageName, object routeValues)
=> RedirectToPage(pageName, routeValues, fragment: null);
/// <summary>
/// Redirects (<see cref="StatusCodes.Status302Found"/>) to the specified <paramref name="pageName"/>
/// using the specified <paramref name="fragment"/>.
/// </summary>
/// <param name="pageName">The name of the page.</param>
/// <param name="fragment">The fragment to add to the URL.</param>
/// <returns>The <see cref="RedirectToPageResult"/>.</returns>
[NonAction]
public virtual RedirectToPageResult RedirectToPage(string pageName, string fragment)
=> RedirectToPage(pageName, routeValues: null, fragment: fragment);
/// <summary>
/// Redirects (<see cref="StatusCodes.Status302Found"/>) to the specified <paramref name="pageName"/>
/// using the specified <paramref name="routeValues"/> and <paramref name="fragment"/>.
/// </summary>
/// <param name="pageName">The name of the page.</param>
/// <param name="routeValues">The parameters for a route.</param>
/// <param name="fragment">The fragment to add to the URL.</param>
/// <returns>The <see cref="RedirectToPageResult"/>.</returns>
[NonAction]
public virtual RedirectToPageResult RedirectToPage(string pageName, object routeValues, string fragment)
=> new RedirectToPageResult(pageName, routeValues, fragment);
/// <summary>
/// Redirects (<see cref="StatusCodes.Status301MovedPermanently"/>) to the specified <paramref name="pageName"/>.
/// </summary>
/// <param name="pageName">The name of the page.</param>
/// <returns>The <see cref="RedirectToPageResult"/> with <see cref="RedirectToPageResult.Permanent"/> set.</returns>
[NonAction]
public virtual RedirectToPageResult RedirectToPagePermanent(string pageName)
=> RedirectToPagePermanent(pageName, routeValues: null);
/// <summary>
/// Redirects (<see cref="StatusCodes.Status301MovedPermanently"/>) to the specified <paramref name="pageName"/>
/// using the specified <paramref name="routeValues"/>.
/// </summary>
/// <param name="pageName">The name of the page.</param>
/// <param name="routeValues">The parameters for a route.</param>
/// <returns>The <see cref="RedirectToPageResult"/> with <see cref="RedirectToPageResult.Permanent"/> set.</returns>
[NonAction]
public virtual RedirectToPageResult RedirectToPagePermanent(string pageName, object routeValues)
=> RedirectToPagePermanent(pageName, routeValues, fragment: null);
/// <summary>
/// Redirects (<see cref="StatusCodes.Status301MovedPermanently"/>) to the specified <paramref name="pageName"/>
/// using the specified <paramref name="fragment"/>.
/// </summary>
/// <param name="pageName">The name of the page.</param>
/// <param name="fragment">The fragment to add to the URL.</param>
/// <returns>The <see cref="RedirectToPageResult"/> with <see cref="RedirectToPageResult.Permanent"/> set.</returns>
[NonAction]
public virtual RedirectToPageResult RedirectToPagePermanent(string pageName, string fragment)
=> RedirectToPagePermanent(pageName, routeValues: null, fragment: fragment);
/// <summary>
/// Redirects (<see cref="StatusCodes.Status301MovedPermanently"/>) to the specified <paramref name="pageName"/>
/// using the specified <paramref name="routeValues"/> and <paramref name="fragment"/>.
/// </summary>
/// <param name="pageName">The name of the page.</param>
/// <param name="routeValues">The parameters for a route.</param>
/// <param name="fragment">The fragment to add to the URL.</param>
/// <returns>The <see cref="RedirectToPageResult"/> with <see cref="RedirectToPageResult.Permanent"/> set.</returns>
[NonAction]
public virtual RedirectToPageResult RedirectToPagePermanent(string pageName, object routeValues, string fragment)
=> new RedirectToPageResult(pageName, routeValues, permanent: true, fragment: fragment);
/// <summary>
/// Redirects (<see cref="StatusCodes.Status307TemporaryRedirect"/>) to the specified page with
/// <see cref="RedirectToRouteResult.Permanent"/> set to false and <see cref="RedirectToRouteResult.PreserveMethod"/>
/// set to true, using the specified <paramref name="pageName"/>, <paramref name="routeValues"/>, and <paramref name="fragment"/>.
/// </summary>
/// <param name="pageName">The name of the page.</param>
/// <param name="routeValues">The route data to use for generating the URL.</param>
/// <param name="fragment">The fragment to add to the URL.</param>
/// <returns>The created <see cref="RedirectToRouteResult"/> for the response.</returns>
[NonAction]
public virtual RedirectToPageResult RedirectToPagePreserveMethod(
string pageName,
object routeValues = null,
string fragment = null)
{
if (pageName == null)
{
throw new ArgumentNullException(nameof(pageName));
}
return new RedirectToPageResult(
pageName: pageName,
routeValues: routeValues,
permanent: false,
preserveMethod: true,
fragment: fragment);
}
/// <summary>
/// Redirects (<see cref="StatusCodes.Status308PermanentRedirect"/>) to the specified route with
/// <see cref="RedirectToRouteResult.Permanent"/> set to true and <see cref="RedirectToRouteResult.PreserveMethod"/>
/// set to true, using the specified <paramref name="pageName"/>, <paramref name="routeValues"/>, and <paramref name="fragment"/>.
/// </summary>
/// <param name="pageName">The name of the page.</param>
/// <param name="routeValues">The route data to use for generating the URL.</param>
/// <param name="fragment">The fragment to add to the URL.</param>
/// <returns>The created <see cref="RedirectToRouteResult"/> for the response.</returns>
[NonAction]
public virtual RedirectToPageResult RedirectToPagePermanentPreserveMethod(
string pageName,
object routeValues = null,
string fragment = null)
{
if (pageName == null)
{
throw new ArgumentNullException(nameof(pageName));
}
return new RedirectToPageResult(
pageName: pageName,
routeValues: routeValues,
permanent: true,
preserveMethod: true,
fragment: fragment);
}
/// <summary> /// <summary>
/// Returns a file with the specified <paramref name="fileContents" /> as content /// Returns a file with the specified <paramref name="fileContents" /> as content
/// (<see cref="StatusCodes.Status200OK"/>) and the specified <paramref name="contentType" /> as the Content-Type. /// (<see cref="StatusCodes.Status200OK"/>) and the specified <paramref name="contentType" /> as the Content-Type.

View File

@ -215,6 +215,7 @@ namespace Microsoft.Extensions.DependencyInjection
services.TryAddSingleton<LocalRedirectResultExecutor>(); services.TryAddSingleton<LocalRedirectResultExecutor>();
services.TryAddSingleton<RedirectToActionResultExecutor>(); services.TryAddSingleton<RedirectToActionResultExecutor>();
services.TryAddSingleton<RedirectToRouteResultExecutor>(); services.TryAddSingleton<RedirectToRouteResultExecutor>();
services.TryAddSingleton<RedirectToPageResultExecutor>();
services.TryAddSingleton<ContentResultExecutor>(); services.TryAddSingleton<ContentResultExecutor>();
// //

View File

@ -69,6 +69,8 @@ namespace Microsoft.AspNetCore.Mvc.Internal
private static readonly Action<ILogger, string[], Exception> _noActionsMatched; private static readonly Action<ILogger, string[], Exception> _noActionsMatched;
private static readonly Action<ILogger, string, Exception> _redirectToPageResultExecuting;
static MvcCoreLoggerExtensions() static MvcCoreLoggerExtensions()
{ {
_actionExecuting = LoggerMessage.Define<string>( _actionExecuting = LoggerMessage.Define<string>(
@ -226,6 +228,11 @@ namespace Microsoft.AspNetCore.Mvc.Internal
1, 1,
"Executing RedirectToRouteResult, redirecting to {Destination} from route {RouteName}."); "Executing RedirectToRouteResult, redirecting to {Destination} from route {RouteName}.");
_redirectToPageResultExecuting = LoggerMessage.Define<string>(
LogLevel.Information,
1,
"Executing RedirectToPageResult, redirecting to {Page}.");
_noActionsMatched = LoggerMessage.Define<string[]>( _noActionsMatched = LoggerMessage.Define<string[]>(
LogLevel.Debug, LogLevel.Debug,
3, 3,
@ -499,6 +506,9 @@ namespace Microsoft.AspNetCore.Mvc.Internal
_redirectToRouteResultExecuting(logger, destination, routeName, null); _redirectToRouteResultExecuting(logger, destination, routeName, null);
} }
public static void RedirectToPageResultExecuting(this ILogger logger, string page)
=> _redirectToPageResultExecuting(logger, page, null);
private class ActionLogScope : IReadOnlyList<KeyValuePair<string, object>> private class ActionLogScope : IReadOnlyList<KeyValuePair<string, object>>
{ {
private readonly ActionDescriptor _action; private readonly ActionDescriptor _action;
@ -539,7 +549,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
public IEnumerator<KeyValuePair<string, object>> GetEnumerator() public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
{ {
for (int i = 0; i < Count; ++i) for (var i = 0; i < Count; ++i)
{ {
yield return this[i]; yield return this[i];
} }

View File

@ -3,11 +3,12 @@
using System; using System;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Core;
using Microsoft.AspNetCore.Mvc.Routing; using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal namespace Microsoft.AspNetCore.Mvc.Internal
{ {
public class RedirectToPageResultExecutor public class RedirectToPageResultExecutor
{ {
@ -42,7 +43,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
if (string.IsNullOrEmpty(destinationUrl)) if (string.IsNullOrEmpty(destinationUrl))
{ {
throw new InvalidOperationException(Resources.FormatNoRoutesMatched(result.PageName)); throw new InvalidOperationException(Resources.FormatNoRoutesMatchedForPage(result.PageName));
} }
_logger.RedirectToPageResultExecuting(result.PageName); _logger.RedirectToPageResultExecuting(result.PageName);

View File

@ -1270,6 +1270,20 @@ namespace Microsoft.AspNetCore.Mvc.Core
internal static string FormatComplexTypeModelBinder_NoParameterlessConstructor_ForProperty(object p0, object p1, object p2) internal static string FormatComplexTypeModelBinder_NoParameterlessConstructor_ForProperty(object p0, object p1, object p2)
=> string.Format(CultureInfo.CurrentCulture, GetString("ComplexTypeModelBinder_NoParameterlessConstructor_ForProperty"), p0, p1, p2); => string.Format(CultureInfo.CurrentCulture, GetString("ComplexTypeModelBinder_NoParameterlessConstructor_ForProperty"), p0, p1, p2);
/// <summary>
/// No page named '{0}' matches the supplied values.
/// </summary>
internal static string NoRoutesMatchedForPage
{
get => GetString("NoRoutesMatchedForPage");
}
/// <summary>
/// No page named '{0}' matches the supplied values.
/// </summary>
internal static string FormatNoRoutesMatchedForPage(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("NoRoutesMatchedForPage"), p0);
private static string GetString(string name, params string[] formatterNames) private static string GetString(string name, params string[] formatterNames)
{ {
var value = _resourceManager.GetString(name); var value = _resourceManager.GetString(name);

View File

@ -2,12 +2,12 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using Microsoft.AspNetCore.Mvc.RazorPages.Internal; using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.Mvc.RazorPages namespace Microsoft.AspNetCore.Mvc
{ {
/// <summary> /// <summary>
/// An <see cref="ActionResult"/> that returns a Found (302) /// An <see cref="ActionResult"/> that returns a Found (302)

View File

@ -297,7 +297,7 @@
<data name="ModelBinding_MissingBindRequiredMember" xml:space="preserve"> <data name="ModelBinding_MissingBindRequiredMember" xml:space="preserve">
<value>A value for the '{0}' property was not provided.</value> <value>A value for the '{0}' property was not provided.</value>
</data> </data>
<data name="ModelBinding_MissingRequestBodyRequiredMember" xml:space="preserve"> <data name="ModelBinding_MissingRequestBodyRequiredMember" xml:space="preserve">
<value>A non-empty request body is required.</value> <value>A non-empty request body is required.</value>
</data> </data>
<data name="ValueProviderResult_NoConverterExists" xml:space="preserve"> <data name="ValueProviderResult_NoConverterExists" xml:space="preserve">
@ -400,4 +400,7 @@
<data name="ComplexTypeModelBinder_NoParameterlessConstructor_ForProperty" xml:space="preserve"> <data name="ComplexTypeModelBinder_NoParameterlessConstructor_ForProperty" xml:space="preserve">
<value>Could not create an instance of type '{0}'. Model bound complex types must not be abstract or value types and must have a parameterless constructor. Alternatively, set the '{1}' property to a non-null value in the '{2}' constructor.</value> <value>Could not create an instance of type '{0}'. Model bound complex types must not be abstract or value types and must have a parameterless constructor. Alternatively, set the '{1}' property to a non-null value in the '{2}' constructor.</value>
</data> </data>
<data name="NoRoutesMatchedForPage" xml:space="preserve">
<value>No page named '{0}' matches the supplied values.</value>
</data>
</root> </root>

View File

@ -3,6 +3,7 @@
using System; using System;
using Microsoft.AspNetCore.Mvc.Routing; using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Routing;
namespace Microsoft.AspNetCore.Mvc namespace Microsoft.AspNetCore.Mvc
{ {
@ -332,5 +333,112 @@ namespace Microsoft.AspNetCore.Mvc
Fragment = fragment Fragment = fragment
}); });
} }
/// <summary>
/// Generates a URL with an absolute path for the specified <paramref name="pageName"/>.
/// </summary>
/// <param name="urlHelper">The <see cref="IUrlHelper"/>.</param>
/// <param name="pageName">The page name to generate the url for.</param>
/// <returns>The generated URL.</returns>
public static string Page(this IUrlHelper urlHelper, string pageName)
=> Page(urlHelper, pageName, values: null);
/// <summary>
/// Generates a URL with an absolute path for the specified <paramref name="pageName"/>.
/// </summary>
/// <param name="urlHelper">The <see cref="IUrlHelper"/>.</param>
/// <param name="pageName">The page name to generate the url for.</param>
/// <param name="values">An object that contains route values.</param>
/// <returns>The generated URL.</returns>
public static string Page(
this IUrlHelper urlHelper,
string pageName,
object values)
=> Page(urlHelper, pageName, values, protocol: null);
/// <summary>
/// Generates a URL with an absolute path for the specified <paramref name="pageName"/>.
/// </summary>
/// <param name="urlHelper">The <see cref="IUrlHelper"/>.</param>
/// <param name="pageName">The page name to generate the url for.</param>
/// <param name="values">An object that contains route values.</param>
/// <param name="protocol">The protocol for the URL, such as "http" or "https".</param>
/// <returns>The generated URL.</returns>
public static string Page(
this IUrlHelper urlHelper,
string pageName,
object values,
string protocol)
=> Page(urlHelper, pageName, values, protocol, host: null, fragment: null);
/// <summary>
/// Generates a URL with an absolute path for the specified <paramref name="pageName"/>.
/// </summary>
/// <param name="urlHelper">The <see cref="IUrlHelper"/>.</param>
/// <param name="pageName">The page name to generate the url for.</param>
/// <param name="values">An object that contains route values.</param>
/// <param name="protocol">The protocol for the URL, such as "http" or "https".</param>
/// <param name="host">The host name for the URL.</param>
/// <returns>The generated URL.</returns>
public static string Page(
this IUrlHelper urlHelper,
string pageName,
object values,
string protocol,
string host)
=> Page(urlHelper, pageName, values, protocol, host, fragment: null);
/// <summary>
/// Generates a URL with an absolute path for the specified <paramref name="pageName"/>.
/// </summary>
/// <param name="urlHelper">The <see cref="IUrlHelper"/>.</param>
/// <param name="pageName">The page name to generate the url for.</param>
/// <param name="values">An object that contains route values.</param>
/// <param name="protocol">The protocol for the URL, such as "http" or "https".</param>
/// <param name="host">The host name for the URL.</param>
/// <param name="fragment">The fragment for the URL.</param>
/// <returns>The generated URL.</returns>
public static string Page(
this IUrlHelper urlHelper,
string pageName,
object values,
string protocol,
string host,
string fragment)
{
if (urlHelper == null)
{
throw new ArgumentNullException(nameof(urlHelper));
}
var routeValues = new RouteValueDictionary(values);
var ambientValues = urlHelper.ActionContext.RouteData.Values;
if (pageName == null)
{
if (!routeValues.ContainsKey("page") &&
ambientValues.TryGetValue("page", out var value))
{
routeValues["page"] = value;
}
}
else
{
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(
routeName: null,
values: routeValues,
protocol: protocol,
host: host,
fragment: fragment);
}
} }
} }

View File

@ -102,7 +102,6 @@ namespace Microsoft.Extensions.DependencyInjection
// Action executors // Action executors
services.TryAddSingleton<PageResultExecutor>(); services.TryAddSingleton<PageResultExecutor>();
services.TryAddSingleton<RedirectToPageResultExecutor>();
services.TryAddTransient<PageSaveTempDataPropertyFilter>(); services.TryAddTransient<PageSaveTempDataPropertyFilter>();
} }

View File

@ -18,7 +18,6 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
private static readonly Action<ILogger, string, double, Exception> _pageExecuted; private static readonly Action<ILogger, string, double, Exception> _pageExecuted;
private static readonly Action<ILogger, object, Exception> _exceptionFilterShortCircuit; private static readonly Action<ILogger, object, Exception> _exceptionFilterShortCircuit;
private static readonly Action<ILogger, object, Exception> _pageFilterShortCircuit; private static readonly Action<ILogger, object, Exception> _pageFilterShortCircuit;
private static readonly Action<ILogger, string, Exception> _redirectToPageResultExecuting;
static PageLoggerExtensions() static PageLoggerExtensions()
{ {
@ -41,11 +40,6 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
LogLevel.Debug, LogLevel.Debug,
3, 3,
"Request was short circuited at page filter '{PageFilter}'."); "Request was short circuited at page filter '{PageFilter}'.");
_redirectToPageResultExecuting = LoggerMessage.Define<string>(
LogLevel.Information,
5,
"Executing RedirectToPageResult, redirecting to {Page}.");
} }
public static IDisposable PageScope(this ILogger logger, ActionDescriptor actionDescriptor) public static IDisposable PageScope(this ILogger logger, ActionDescriptor actionDescriptor)
@ -87,9 +81,6 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
_pageFilterShortCircuit(logger, filter, null); _pageFilterShortCircuit(logger, filter, null);
} }
public static void RedirectToPageResultExecuting(this ILogger logger, string page)
=> _redirectToPageResultExecuting(logger, page, null);
private class PageLogScope : IReadOnlyList<KeyValuePair<string, object>> private class PageLogScope : IReadOnlyList<KeyValuePair<string, object>>
{ {
private readonly ActionDescriptor _action; private readonly ActionDescriptor _action;

View File

@ -950,7 +950,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
/// Redirects (<see cref="StatusCodes.Status302Found"/>) to the current page. /// Redirects (<see cref="StatusCodes.Status302Found"/>) to the current page.
/// </summary> /// </summary>
/// <returns>The <see cref="RedirectToPageResult"/>.</returns> /// <returns>The <see cref="RedirectToPageResult"/>.</returns>
protected RedirectToPageResult RedirectToPage() public virtual RedirectToPageResult RedirectToPage()
=> RedirectToPage(pageName: null); => RedirectToPage(pageName: null);
/// <summary> /// <summary>
@ -958,7 +958,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
/// </summary> /// </summary>
/// <param name="routeValues">The parameters for a route.</param> /// <param name="routeValues">The parameters for a route.</param>
/// <returns>The <see cref="RedirectToPageResult"/>.</returns> /// <returns>The <see cref="RedirectToPageResult"/>.</returns>
protected RedirectToPageResult RedirectToPage(object routeValues) public virtual RedirectToPageResult RedirectToPage(object routeValues)
=> RedirectToPage(pageName: null, routeValues: routeValues); => RedirectToPage(pageName: null, routeValues: routeValues);
/// <summary> /// <summary>
@ -966,7 +966,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
/// </summary> /// </summary>
/// <param name="pageName">The name of the page.</param> /// <param name="pageName">The name of the page.</param>
/// <returns>The <see cref="RedirectToPageResult"/>.</returns> /// <returns>The <see cref="RedirectToPageResult"/>.</returns>
protected RedirectToPageResult RedirectToPage(string pageName) public virtual RedirectToPageResult RedirectToPage(string pageName)
=> RedirectToPage(pageName, routeValues: null); => RedirectToPage(pageName, routeValues: null);
/// <summary> /// <summary>
@ -976,7 +976,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
/// <param name="pageName">The name of the page.</param> /// <param name="pageName">The name of the page.</param>
/// <param name="routeValues">The parameters for a route.</param> /// <param name="routeValues">The parameters for a route.</param>
/// <returns>The <see cref="RedirectToPageResult"/>.</returns> /// <returns>The <see cref="RedirectToPageResult"/>.</returns>
protected RedirectToPageResult RedirectToPage(string pageName, object routeValues) public virtual RedirectToPageResult RedirectToPage(string pageName, object routeValues)
=> RedirectToPage(pageName, routeValues, fragment: null); => RedirectToPage(pageName, routeValues, fragment: null);
/// <summary> /// <summary>
@ -986,7 +986,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
/// <param name="pageName">The name of the page.</param> /// <param name="pageName">The name of the page.</param>
/// <param name="fragment">The fragment to add to the URL.</param> /// <param name="fragment">The fragment to add to the URL.</param>
/// <returns>The <see cref="RedirectToPageResult"/>.</returns> /// <returns>The <see cref="RedirectToPageResult"/>.</returns>
protected RedirectToPageResult RedirectToPage(string pageName, string fragment) public virtual RedirectToPageResult RedirectToPage(string pageName, string fragment)
=> RedirectToPage(pageName, routeValues: null, fragment: fragment); => RedirectToPage(pageName, routeValues: null, fragment: fragment);
/// <summary> /// <summary>
@ -997,7 +997,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
/// <param name="routeValues">The parameters for a route.</param> /// <param name="routeValues">The parameters for a route.</param>
/// <param name="fragment">The fragment to add to the URL.</param> /// <param name="fragment">The fragment to add to the URL.</param>
/// <returns>The <see cref="RedirectToPageResult"/>.</returns> /// <returns>The <see cref="RedirectToPageResult"/>.</returns>
protected RedirectToPageResult RedirectToPage(string pageName, object routeValues, string fragment) public virtual RedirectToPageResult RedirectToPage(string pageName, object routeValues, string fragment)
=> new RedirectToPageResult(pageName, routeValues, fragment); => new RedirectToPageResult(pageName, routeValues, fragment);
/// <summary> /// <summary>
@ -1005,7 +1005,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
/// </summary> /// </summary>
/// <param name="pageName">The name of the page.</param> /// <param name="pageName">The name of the page.</param>
/// <returns>The <see cref="RedirectToPageResult"/> with <see cref="RedirectToPageResult.Permanent"/> set.</returns> /// <returns>The <see cref="RedirectToPageResult"/> with <see cref="RedirectToPageResult.Permanent"/> set.</returns>
protected RedirectToPageResult RedirectToPagePermanent(string pageName) public virtual RedirectToPageResult RedirectToPagePermanent(string pageName)
=> RedirectToPagePermanent(pageName, routeValues: null); => RedirectToPagePermanent(pageName, routeValues: null);
/// <summary> /// <summary>
@ -1015,7 +1015,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
/// <param name="pageName">The name of the page.</param> /// <param name="pageName">The name of the page.</param>
/// <param name="routeValues">The parameters for a route.</param> /// <param name="routeValues">The parameters for a route.</param>
/// <returns>The <see cref="RedirectToPageResult"/> with <see cref="RedirectToPageResult.Permanent"/> set.</returns> /// <returns>The <see cref="RedirectToPageResult"/> with <see cref="RedirectToPageResult.Permanent"/> set.</returns>
protected RedirectToPageResult RedirectToPagePermanent(string pageName, object routeValues) public virtual RedirectToPageResult RedirectToPagePermanent(string pageName, object routeValues)
=> RedirectToPagePermanent(pageName, routeValues, fragment: null); => RedirectToPagePermanent(pageName, routeValues, fragment: null);
/// <summary> /// <summary>
@ -1025,7 +1025,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
/// <param name="pageName">The name of the page.</param> /// <param name="pageName">The name of the page.</param>
/// <param name="fragment">The fragment to add to the URL.</param> /// <param name="fragment">The fragment to add to the URL.</param>
/// <returns>The <see cref="RedirectToPageResult"/> with <see cref="RedirectToPageResult.Permanent"/> set.</returns> /// <returns>The <see cref="RedirectToPageResult"/> with <see cref="RedirectToPageResult.Permanent"/> set.</returns>
protected RedirectToPageResult RedirectToPagePermanent(string pageName, string fragment) public virtual RedirectToPageResult RedirectToPagePermanent(string pageName, string fragment)
=> RedirectToPagePermanent(pageName, routeValues: null, fragment: fragment); => RedirectToPagePermanent(pageName, routeValues: null, fragment: fragment);
/// <summary> /// <summary>

View File

@ -1,121 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Routing;
namespace Microsoft.AspNetCore.Mvc
{
/// <summary>
/// Razor page specific extensions for <see cref="IUrlHelper"/>.
/// </summary>
public static class PageUrlHelperExtensions
{
/// <summary>
/// Generates a URL with an absolute path for the specified <paramref name="pageName"/>.
/// </summary>
/// <param name="urlHelper">The <see cref="IUrlHelper"/>.</param>
/// <param name="pageName">The page name to generate the url for.</param>
/// <returns>The generated URL.</returns>
public static string Page(this IUrlHelper urlHelper, string pageName)
=> Page(urlHelper, pageName, values: null);
/// <summary>
/// Generates a URL with an absolute path for the specified <paramref name="pageName"/>.
/// </summary>
/// <param name="urlHelper">The <see cref="IUrlHelper"/>.</param>
/// <param name="pageName">The page name to generate the url for.</param>
/// <param name="values">An object that contains route values.</param>
/// <returns>The generated URL.</returns>
public static string Page(
this IUrlHelper urlHelper,
string pageName,
object values)
=> Page(urlHelper, pageName, values, protocol: null);
/// <summary>
/// Generates a URL with an absolute path for the specified <paramref name="pageName"/>.
/// </summary>
/// <param name="urlHelper">The <see cref="IUrlHelper"/>.</param>
/// <param name="pageName">The page name to generate the url for.</param>
/// <param name="values">An object that contains route values.</param>
/// <param name="protocol">The protocol for the URL, such as "http" or "https".</param>
/// <returns>The generated URL.</returns>
public static string Page(
this IUrlHelper urlHelper,
string pageName,
object values,
string protocol)
=> Page(urlHelper, pageName, values, protocol, host: null, fragment: null);
/// <summary>
/// Generates a URL with an absolute path for the specified <paramref name="pageName"/>.
/// </summary>
/// <param name="urlHelper">The <see cref="IUrlHelper"/>.</param>
/// <param name="pageName">The page name to generate the url for.</param>
/// <param name="values">An object that contains route values.</param>
/// <param name="protocol">The protocol for the URL, such as "http" or "https".</param>
/// <param name="host">The host name for the URL.</param>
/// <returns>The generated URL.</returns>
public static string Page(
this IUrlHelper urlHelper,
string pageName,
object values,
string protocol,
string host)
=> Page(urlHelper, pageName, values, protocol, host, fragment: null);
/// <summary>
/// Generates a URL with an absolute path for the specified <paramref name="pageName"/>.
/// </summary>
/// <param name="urlHelper">The <see cref="IUrlHelper"/>.</param>
/// <param name="pageName">The page name to generate the url for.</param>
/// <param name="values">An object that contains route values.</param>
/// <param name="protocol">The protocol for the URL, such as "http" or "https".</param>
/// <param name="host">The host name for the URL.</param>
/// <param name="fragment">The fragment for the URL.</param>
/// <returns>The generated URL.</returns>
public static string Page(
this IUrlHelper urlHelper,
string pageName,
object values,
string protocol,
string host,
string fragment)
{
if (urlHelper == null)
{
throw new ArgumentNullException(nameof(urlHelper));
}
var routeValues = new RouteValueDictionary(values);
var ambientValues = urlHelper.ActionContext.RouteData.Values;
if (pageName == null)
{
if (!routeValues.ContainsKey("page") &&
ambientValues.TryGetValue("page", out var value))
{
routeValues["page"] = value;
}
}
else
{
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(
routeName: null,
values: routeValues,
protocol: protocol,
host: host,
fragment: fragment);
}
}
}

View File

@ -122,20 +122,6 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
internal static string FormatPathMustBeAnAppRelativePath() internal static string FormatPathMustBeAnAppRelativePath()
=> GetString("PathMustBeAnAppRelativePath"); => GetString("PathMustBeAnAppRelativePath");
/// <summary>
/// No page named '{0}' matches the supplied values.
/// </summary>
internal static string NoRoutesMatched
{
get => GetString("NoRoutesMatched");
}
/// <summary>
/// No page named '{0}' matches the supplied values.
/// </summary>
internal static string FormatNoRoutesMatched(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("NoRoutesMatched"), p0);
private static string GetString(string name, params string[] formatterNames) private static string GetString(string name, params string[] formatterNames)
{ {
var value = _resourceManager.GetString(name); var value = _resourceManager.GetString(name);

View File

@ -141,7 +141,4 @@
<data name="PathMustBeAnAppRelativePath" xml:space="preserve"> <data name="PathMustBeAnAppRelativePath" xml:space="preserve">
<value>Path must be an application relative path that starts with a forward slash '/'.</value> <value>Path must be an application relative path that starts with a forward slash '/'.</value>
</data> </data>
<data name="NoRoutesMatched" xml:space="preserve">
<value>No page named '{0}' matches the supplied values.</value>
</data>
</root> </root>

View File

@ -986,6 +986,65 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
Assert.Equal(expected, resultPermanent.RouteValues); Assert.Equal(expected, resultPermanent.RouteValues);
} }
[Fact]
public void RedirectToPagePreserveMethod_WithParameterUrl_SetsRedirectResultPreserveMethod()
{
// Arrange
var pageModel = new TestableController();
var url = "/test/url";
// Act
var result = pageModel.RedirectToPagePreserveMethod(url);
// Assert
Assert.IsType<RedirectToPageResult>(result);
Assert.True(result.PreserveMethod);
Assert.False(result.Permanent);
Assert.Same(url, result.PageName);
}
[Theory]
[MemberData(nameof(RedirectTestData))]
public void RedirectToPagePreserveMethod_SetsResultProperties(
object routeValues,
IEnumerable<KeyValuePair<string, object>> expected)
{
// Arrange
var pageModel = new TestableController();
var pageName = "CustomRouteName";
// Act
var resultPermanent = pageModel.RedirectToPagePreserveMethod(pageName, routeValues);
// Assert
Assert.IsType<RedirectToPageResult>(resultPermanent);
Assert.True(resultPermanent.PreserveMethod);
Assert.False(resultPermanent.Permanent);
Assert.Same(pageName, resultPermanent.PageName);
Assert.Equal(expected, resultPermanent.RouteValues);
}
[Theory]
[MemberData(nameof(RedirectTestData))]
public void RedirectToPagePermanentPreserveMethod_SetsResultProperties(
object routeValues,
IEnumerable<KeyValuePair<string, object>> expected)
{
// Arrange
var pageModel = new TestableController();
var routeName = "CustomRouteName";
// Act
var resultPermanent = pageModel.RedirectToPagePermanentPreserveMethod(routeName, routeValues);
// Assert
Assert.IsType<RedirectToPageResult>(resultPermanent);
Assert.True(resultPermanent.PreserveMethod);
Assert.True(resultPermanent.Permanent);
Assert.Same(routeName, resultPermanent.PageName);
Assert.Equal(expected, resultPermanent.RouteValues);
}
[Theory] [Theory]
[MemberData(nameof(RedirectTestData))] [MemberData(nameof(RedirectTestData))]
public void RedirectToRoutePermanentPreserveMethod_WithParameterRouteNameAndRouteValues_SetsResultProperties( public void RedirectToRoutePermanentPreserveMethod_WithParameterRouteNameAndRouteValues_SetsResultProperties(

View File

@ -4,10 +4,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.RazorPages.Internal; using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Routing; using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing;
@ -17,7 +17,7 @@ using Microsoft.Extensions.Logging.Abstractions;
using Moq; using Moq;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Mvc.RazorPages namespace Microsoft.AspNetCore.Mvc
{ {
public class RedirectToPageResultTest public class RedirectToPageResultTest
{ {

View File

@ -1031,6 +1031,345 @@ namespace Microsoft.AspNetCore.Mvc.Routing
Assert.Same(urlHelper, actionContext.HttpContext.Items[typeof(IUrlHelper)] as IUrlHelper); Assert.Same(urlHelper, actionContext.HttpContext.Items[typeof(IUrlHelper)] as IUrlHelper);
} }
[Fact]
public void Page_WithName_Works()
{
// Arrange
UrlRouteContext actual = null;
var routeData = new RouteData
{
Values =
{
{ "page", "ambient-page" },
}
};
var actionContext = new ActionContext
{
RouteData = routeData,
};
var urlHelper = CreateMockUrlHelper(actionContext);
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
.Callback((UrlRouteContext context) => actual = context);
// Act
urlHelper.Object.Page("TestPage");
// Assert
urlHelper.Verify();
Assert.NotNull(actual);
Assert.Null(actual.RouteName);
Assert.Collection(Assert.IsType<RouteValueDictionary>(actual.Values),
value =>
{
Assert.Equal("page", value.Key);
Assert.Equal("TestPage", value.Value);
});
Assert.Null(actual.Host);
Assert.Null(actual.Protocol);
Assert.Null(actual.Fragment);
}
public static TheoryData Page_WithNameAndRouteValues_WorksData
{
get => new TheoryData<object>
{
{ new { id = 10 } },
{
new Dictionary<string, object>
{
["id"] = 10,
}
},
{
new RouteValueDictionary
{
["id"] = 10,
}
},
};
}
[Theory]
[MemberData(nameof(Page_WithNameAndRouteValues_WorksData))]
public void Page_WithNameAndRouteValues_Works(object values)
{
// Arrange
UrlRouteContext actual = null;
var urlHelper = CreateMockUrlHelper();
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
.Callback((UrlRouteContext context) => actual = context);
// Act
urlHelper.Object.Page("TestPage", values);
// 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(10, value.Value);
},
value =>
{
Assert.Equal("page", value.Key);
Assert.Equal("TestPage", value.Value);
});
Assert.Null(actual.Host);
Assert.Null(actual.Protocol);
Assert.Null(actual.Fragment);
}
[Fact]
public void Page_WithNameRouteValuesAndProtocol_Works()
{
// Arrange
UrlRouteContext actual = null;
var urlHelper = CreateMockUrlHelper();
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
.Callback((UrlRouteContext context) => actual = context);
// Act
urlHelper.Object.Page("TestPage", new { id = 13 }, "https");
// 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("TestPage", value.Value);
});
Assert.Equal("https", actual.Protocol);
Assert.Null(actual.Host);
Assert.Null(actual.Fragment);
}
[Fact]
public void Page_WithNameRouteValuesProtocolAndHost_Works()
{
// Arrange
UrlRouteContext actual = null;
var urlHelper = CreateMockUrlHelper();
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
.Callback((UrlRouteContext context) => actual = context);
// Act
urlHelper.Object.Page("TestPage", new { id = 13 }, "https", "mytesthost");
// 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("TestPage", value.Value);
});
Assert.Equal("https", actual.Protocol);
Assert.Equal("mytesthost", actual.Host);
Assert.Null(actual.Fragment);
}
[Fact]
public void Page_WithNameRouteValuesProtocolHostAndFragment_Works()
{
// Arrange
UrlRouteContext actual = null;
var urlHelper = CreateMockUrlHelper();
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
.Callback((UrlRouteContext context) => actual = context);
// Act
urlHelper.Object.Page("TestPage", 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("TestPage", value.Value);
});
Assert.Equal("https", actual.Protocol);
Assert.Equal("mytesthost", actual.Host);
Assert.Equal("#toc", actual.Fragment);
}
[Fact]
public void Page_UsesAmbientRouteValue_WhenPageIsNull()
{
// Arrange
UrlRouteContext actual = null;
var routeData = new RouteData
{
Values =
{
{ "page", "ambient-page" },
}
};
var actionContext = new ActionContext
{
RouteData = routeData,
};
var urlHelper = CreateMockUrlHelper(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);
});
Assert.Equal("https", actual.Protocol);
Assert.Equal("mytesthost", actual.Host);
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 = CreateMockUrlHelper(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 = CreateMockUrlHelper(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> CreateMockUrlHelper(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;
}
private static HttpContext CreateHttpContext( private static HttpContext CreateHttpContext(
IServiceProvider services, IServiceProvider services,
string appRoot) string appRoot)

View File

@ -1,353 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Routing;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.RazorPages
{
public class PageUrlHelperExtensionsTest
{
[Fact]
public void Page_WithName_Works()
{
// Arrange
UrlRouteContext actual = null;
var routeData = new RouteData
{
Values =
{
{ "page", "ambient-page" },
}
};
var actionContext = new ActionContext
{
RouteData = routeData,
};
var urlHelper = CreateUrlHelper(actionContext);
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
.Callback((UrlRouteContext context) => actual = context);
// Act
urlHelper.Object.Page("TestPage");
// Assert
urlHelper.Verify();
Assert.NotNull(actual);
Assert.Null(actual.RouteName);
Assert.Collection(Assert.IsType<RouteValueDictionary>(actual.Values),
value =>
{
Assert.Equal("page", value.Key);
Assert.Equal("TestPage", value.Value);
});
Assert.Null(actual.Host);
Assert.Null(actual.Protocol);
Assert.Null(actual.Fragment);
}
public static TheoryData Page_WithNameAndRouteValues_WorksData
{
get => new TheoryData<object>
{
{ new { id = 10 } },
{
new Dictionary<string, object>
{
["id"] = 10,
}
},
{
new RouteValueDictionary
{
["id"] = 10,
}
},
};
}
[Theory]
[MemberData(nameof(Page_WithNameAndRouteValues_WorksData))]
public void Page_WithNameAndRouteValues_Works(object values)
{
// Arrange
UrlRouteContext actual = null;
var urlHelper = CreateUrlHelper();
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
.Callback((UrlRouteContext context) => actual = context);
// Act
urlHelper.Object.Page("TestPage", values);
// 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(10, value.Value);
},
value =>
{
Assert.Equal("page", value.Key);
Assert.Equal("TestPage", value.Value);
});
Assert.Null(actual.Host);
Assert.Null(actual.Protocol);
Assert.Null(actual.Fragment);
}
[Fact]
public void Page_WithNameRouteValuesAndProtocol_Works()
{
// Arrange
UrlRouteContext actual = null;
var urlHelper = CreateUrlHelper();
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
.Callback((UrlRouteContext context) => actual = context);
// Act
urlHelper.Object.Page("TestPage", new { id = 13 }, "https");
// 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("TestPage", value.Value);
});
Assert.Equal("https", actual.Protocol);
Assert.Null(actual.Host);
Assert.Null(actual.Fragment);
}
[Fact]
public void Page_WithNameRouteValuesProtocolAndHost_Works()
{
// Arrange
UrlRouteContext actual = null;
var urlHelper = CreateUrlHelper();
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
.Callback((UrlRouteContext context) => actual = context);
// Act
urlHelper.Object.Page("TestPage", new { id = 13 }, "https", "mytesthost");
// 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("TestPage", value.Value);
});
Assert.Equal("https", actual.Protocol);
Assert.Equal("mytesthost", actual.Host);
Assert.Null(actual.Fragment);
}
[Fact]
public void Page_WithNameRouteValuesProtocolHostAndFragment_Works()
{
// Arrange
UrlRouteContext actual = null;
var urlHelper = CreateUrlHelper();
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
.Callback((UrlRouteContext context) => actual = context);
// Act
urlHelper.Object.Page("TestPage", 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("TestPage", value.Value);
});
Assert.Equal("https", actual.Protocol);
Assert.Equal("mytesthost", actual.Host);
Assert.Equal("#toc", actual.Fragment);
}
[Fact]
public void Page_UsesAmbientRouteValue_WhenPageIsNull()
{
// Arrange
UrlRouteContext actual = null;
var routeData = new RouteData
{
Values =
{
{ "page", "ambient-page" },
}
};
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);
});
Assert.Equal("https", actual.Protocol);
Assert.Equal("mytesthost", actual.Host);
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;
}
}
}

View File

@ -8,9 +8,9 @@ namespace RazorPagesWebSite
public class RedirectController : Controller public class RedirectController : Controller
{ {
[HttpGet("/RedirectToPage")] [HttpGet("/RedirectToPage")]
public IActionResult RedirectToPage() public IActionResult RedirectToPageAction()
{ {
return RedirectToRoute(new { page = "/RedirectToController", param = 17 }); return RedirectToPage("/RedirectToController", new { param = 17 });
} }
} }
} }

View File

@ -3,6 +3,6 @@
@functions { @functions {
public IActionResult OnGet() public IActionResult OnGet()
{ {
return new RedirectToRouteResult(new { controller = "Redirect", action = "RedirectToPage", param = 92 }); return new RedirectToRouteResult(new { controller = "Redirect", action = "RedirectToPageAction", param = 92 });
} }
} }