[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>
/// 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.

View File

@ -215,6 +215,7 @@ namespace Microsoft.Extensions.DependencyInjection
services.TryAddSingleton<LocalRedirectResultExecutor>();
services.TryAddSingleton<RedirectToActionResultExecutor>();
services.TryAddSingleton<RedirectToRouteResultExecutor>();
services.TryAddSingleton<RedirectToPageResultExecutor>();
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> _redirectToPageResultExecuting;
static MvcCoreLoggerExtensions()
{
_actionExecuting = LoggerMessage.Define<string>(
@ -226,6 +228,11 @@ namespace Microsoft.AspNetCore.Mvc.Internal
1,
"Executing RedirectToRouteResult, redirecting to {Destination} from route {RouteName}.");
_redirectToPageResultExecuting = LoggerMessage.Define<string>(
LogLevel.Information,
1,
"Executing RedirectToPageResult, redirecting to {Page}.");
_noActionsMatched = LoggerMessage.Define<string[]>(
LogLevel.Debug,
3,
@ -499,6 +506,9 @@ namespace Microsoft.AspNetCore.Mvc.Internal
_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 readonly ActionDescriptor _action;
@ -539,7 +549,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
{
for (int i = 0; i < Count; ++i)
for (var i = 0; i < Count; ++i)
{
yield return this[i];
}

View File

@ -3,11 +3,12 @@
using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Core;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
namespace Microsoft.AspNetCore.Mvc.Internal
{
public class RedirectToPageResultExecutor
{
@ -42,7 +43,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
if (string.IsNullOrEmpty(destinationUrl))
{
throw new InvalidOperationException(Resources.FormatNoRoutesMatched(result.PageName));
throw new InvalidOperationException(Resources.FormatNoRoutesMatchedForPage(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)
=> 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)
{
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.
using System;
using Microsoft.AspNetCore.Mvc.RazorPages.Internal;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.Mvc.RazorPages
namespace Microsoft.AspNetCore.Mvc
{
/// <summary>
/// An <see cref="ActionResult"/> that returns a Found (302)

View File

@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
@ -26,36 +26,36 @@
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
@ -297,7 +297,7 @@
<data name="ModelBinding_MissingBindRequiredMember" xml:space="preserve">
<value>A value for the '{0}' property was not provided.</value>
</data>
<data name="ModelBinding_MissingRequestBodyRequiredMember" xml:space="preserve">
<data name="ModelBinding_MissingRequestBodyRequiredMember" xml:space="preserve">
<value>A non-empty request body is required.</value>
</data>
<data name="ValueProviderResult_NoConverterExists" xml:space="preserve">
@ -400,4 +400,7 @@
<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>
</data>
<data name="NoRoutesMatchedForPage" xml:space="preserve">
<value>No page named '{0}' matches the supplied values.</value>
</data>
</root>

View File

@ -3,6 +3,7 @@
using System;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Routing;
namespace Microsoft.AspNetCore.Mvc
{
@ -332,5 +333,112 @@ namespace Microsoft.AspNetCore.Mvc
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
services.TryAddSingleton<PageResultExecutor>();
services.TryAddSingleton<RedirectToPageResultExecutor>();
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, object, Exception> _exceptionFilterShortCircuit;
private static readonly Action<ILogger, object, Exception> _pageFilterShortCircuit;
private static readonly Action<ILogger, string, Exception> _redirectToPageResultExecuting;
static PageLoggerExtensions()
{
@ -41,11 +40,6 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
LogLevel.Debug,
3,
"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)
@ -87,9 +81,6 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
_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 readonly ActionDescriptor _action;

View File

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

View File

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

View File

@ -986,6 +986,65 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
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]
[MemberData(nameof(RedirectTestData))]
public void RedirectToRoutePermanentPreserveMethod_WithParameterRouteNameAndRouteValues_SetsResultProperties(

View File

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

View File

@ -1031,6 +1031,345 @@ namespace Microsoft.AspNetCore.Mvc.Routing
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(
IServiceProvider services,
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
{
[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 {
public IActionResult OnGet()
{
return new RedirectToRouteResult(new { controller = "Redirect", action = "RedirectToPage", param = 92 });
return new RedirectToRouteResult(new { controller = "Redirect", action = "RedirectToPageAction", param = 92 });
}
}