Merge pull request #809 from dotnet-maestro-bot/merge/release/2.2-to-master

[automated] Merge branch 'release/2.2' => 'master'
This commit is contained in:
Ryan Nowak 2018-09-22 16:37:23 -07:00 committed by GitHub
commit 362157cf24
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 572 additions and 201 deletions

View File

@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Routing
/// Defines a contract to generate a URL from a template. /// Defines a contract to generate a URL from a template.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// A <see cref="LinkGenerationTemplate"/> can be created from <see cref="LinkGenerator.GetTemplateByAddress{TAddress}(TAddress)"/> /// A <see cref="LinkGenerationTemplate"/> can be created from <see cref="LinkGenerator.GetTemplateByAddress{TAddress}(TAddress, LinkGenerationTemplateOptions)"/>
/// by supplying an address value which has matching endpoints. The returned <see cref="LinkGenerationTemplate"/> /// by supplying an address value which has matching endpoints. The returned <see cref="LinkGenerationTemplate"/>
/// will be bound to the endpoints matching the address that was originally provided. /// will be bound to the endpoints matching the address that was originally provided.
/// </remarks> /// </remarks>
@ -20,6 +20,9 @@ namespace Microsoft.AspNetCore.Routing
/// </summary> /// </summary>
/// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param> /// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
/// <param name="values">The route values. Used to expand parameters in the route template. Optional.</param> /// <param name="values">The route values. Used to expand parameters in the route template. Optional.</param>
/// <param name="pathBase">
/// An optional URI path base. Prepended to the path in the resulting URI. If not provided, the value of <see cref="HttpRequest.PathBase"/> will be used.
/// </param>
/// <param name="fragment">An optional URI fragment. Appended to the resulting URI.</param> /// <param name="fragment">An optional URI fragment. Appended to the resulting URI.</param>
/// <param name="options"> /// <param name="options">
/// An optional <see cref="LinkOptions"/>. Settings on provided object override the settings with matching /// An optional <see cref="LinkOptions"/>. Settings on provided object override the settings with matching
@ -29,6 +32,7 @@ namespace Microsoft.AspNetCore.Routing
public abstract string GetPath( public abstract string GetPath(
HttpContext httpContext, HttpContext httpContext,
object values, object values,
PathString? pathBase = default,
FragmentString fragment = default, FragmentString fragment = default,
LinkOptions options = default); LinkOptions options = default);
@ -54,6 +58,15 @@ namespace Microsoft.AspNetCore.Routing
/// </summary> /// </summary>
/// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param> /// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
/// <param name="values">The route values. Used to expand parameters in the route template. Optional.</param> /// <param name="values">The route values. Used to expand parameters in the route template. Optional.</param>
/// <param name="scheme">
/// The URI scheme, applied to the resulting URI. Optional. If not provided, the value of <see cref="HttpRequest.Scheme"/> will be used.
/// </param>
/// <param name="host">
/// The URI host/authority, applied to the resulting URI. Optional. If not provided, the value <see cref="HttpRequest.Host"/> will be used.
/// </param>
/// <param name="pathBase">
/// An optional URI path base. Prepended to the path in the resulting URI. If not provided, the value of <see cref="HttpRequest.PathBase"/> will be used.
/// </param>
/// <param name="fragment">An optional URI fragment. Appended to the resulting URI.</param> /// <param name="fragment">An optional URI fragment. Appended to the resulting URI.</param>
/// <param name="options"> /// <param name="options">
/// An optional <see cref="LinkOptions"/>. Settings on provided object override the settings with matching /// An optional <see cref="LinkOptions"/>. Settings on provided object override the settings with matching
@ -63,6 +76,9 @@ namespace Microsoft.AspNetCore.Routing
public abstract string GetUri( public abstract string GetUri(
HttpContext httpContext, HttpContext httpContext,
object values, object values,
string scheme = default,
HostString? host = default,
PathString? pathBase = default,
FragmentString fragment = default, FragmentString fragment = default,
LinkOptions options = default); LinkOptions options = default);

View File

@ -0,0 +1,17 @@
// 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.
namespace Microsoft.AspNetCore.Routing
{
/// <summary>
/// Contains options for creating a <see cref="LinkGenerationTemplate" />.
/// </summary>
public class LinkGenerationTemplateOptions
{
/// <summary>
/// Gets or sets a value indicating whether the template will use route values from the current request
/// when generating a URI.
/// </summary>
public bool UseAmbientValues { get; set; }
}
}

View File

@ -25,12 +25,16 @@ namespace Microsoft.AspNetCore.Routing
public abstract class LinkGenerator public abstract class LinkGenerator
{ {
/// <summary> /// <summary>
/// Generates a URI with an absolute path based on the provided values. /// Generates a URI with an absolute path based on the provided values and <see cref="HttpContext"/>.
/// </summary> /// </summary>
/// <typeparam name="TAddress">The address type.</typeparam> /// <typeparam name="TAddress">The address type.</typeparam>
/// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param> /// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
/// <param name="address">The address value. Used to resolve endpoints.</param> /// <param name="address">The address value. Used to resolve endpoints.</param>
/// <param name="values">The route values. Used to expand parameters in the route template. Optional.</param> /// <param name="values">The route values. Used to expand parameters in the route template. Optional.</param>
/// <param name="ambientValues">The values associated with the current request. Optional.</param>
/// <param name="pathBase">
/// An optional URI path base. Prepended to the path in the resulting URI. If not provided, the value of <see cref="HttpRequest.PathBase"/> will be used.
/// </param>
/// <param name="fragment">An optional URI fragment. Appended to the resulting URI.</param> /// <param name="fragment">An optional URI fragment. Appended to the resulting URI.</param>
/// <param name="options"> /// <param name="options">
/// An optional <see cref="LinkOptions"/>. Settings on provided object override the settings with matching /// An optional <see cref="LinkOptions"/>. Settings on provided object override the settings with matching
@ -41,6 +45,8 @@ namespace Microsoft.AspNetCore.Routing
HttpContext httpContext, HttpContext httpContext,
TAddress address, TAddress address,
RouteValueDictionary values, RouteValueDictionary values,
RouteValueDictionary ambientValues = default,
PathString? pathBase = default,
FragmentString fragment = default, FragmentString fragment = default,
LinkOptions options = default); LinkOptions options = default);
@ -65,12 +71,22 @@ namespace Microsoft.AspNetCore.Routing
LinkOptions options = default); LinkOptions options = default);
/// <summary> /// <summary>
/// Generates an absolute URI based on the provided values. /// Generates an absolute URI based on the provided values and <see cref="HttpContext"/>.
/// </summary> /// </summary>
/// <typeparam name="TAddress">The address type.</typeparam> /// <typeparam name="TAddress">The address type.</typeparam>
/// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param> /// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
/// <param name="address">The address value. Used to resolve endpoints.</param> /// <param name="address">The address value. Used to resolve endpoints.</param>
/// <param name="values">The route values. Used to expand parameters in the route template. Optional.</param> /// <param name="values">The route values. Used to expand parameters in the route template. Optional.</param>
/// <param name="ambientValues">The values associated with the current request. Optional.</param>
/// <param name="scheme">
/// The URI scheme, applied to the resulting URI. Optional. If not provided, the value of <see cref="HttpRequest.Scheme"/> will be used.
/// </param>
/// <param name="host">
/// The URI host/authority, applied to the resulting URI. Optional. If not provided, the value <see cref="HttpRequest.Host"/> will be used.
/// </param>
/// <param name="pathBase">
/// An optional URI path base. Prepended to the path in the resulting URI. If not provided, the value of <see cref="HttpRequest.PathBase"/> will be used.
/// </param>
/// <param name="fragment">An optional URI fragment. Appended to the resulting URI.</param> /// <param name="fragment">An optional URI fragment. Appended to the resulting URI.</param>
/// <param name="options"> /// <param name="options">
/// An optional <see cref="LinkOptions"/>. Settings on provided object override the settings with matching /// An optional <see cref="LinkOptions"/>. Settings on provided object override the settings with matching
@ -81,6 +97,10 @@ namespace Microsoft.AspNetCore.Routing
HttpContext httpContext, HttpContext httpContext,
TAddress address, TAddress address,
RouteValueDictionary values, RouteValueDictionary values,
RouteValueDictionary ambientValues = default,
string scheme = default,
HostString? host = default,
PathString? pathBase = default,
FragmentString fragment = default, FragmentString fragment = default,
LinkOptions options = default); LinkOptions options = default);
@ -113,9 +133,10 @@ namespace Microsoft.AspNetCore.Routing
/// </summary> /// </summary>
/// <typeparam name="TAddress">The address type.</typeparam> /// <typeparam name="TAddress">The address type.</typeparam>
/// <param name="address">The address value. Used to resolve endpoints.</param> /// <param name="address">The address value. Used to resolve endpoints.</param>
/// <param name="options">Options for the created <see cref="LinkGenerationTemplate"/>.</param>
/// <returns> /// <returns>
/// A <see cref="LinkGenerationTemplate"/> if one or more endpoints matching the address can be found, otherwise <c>null</c>. /// A <see cref="LinkGenerationTemplate"/> if one or more endpoints matching the address can be found, otherwise <c>null</c>.
/// </returns> /// </returns>
public abstract LinkGenerationTemplate GetTemplateByAddress<TAddress>(TAddress address); public abstract LinkGenerationTemplate GetTemplateByAddress<TAddress>(TAddress address, LinkGenerationTemplateOptions options = null);
} }
} }

View File

@ -1,29 +1,33 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Http;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Routing namespace Microsoft.AspNetCore.Routing
{ {
internal sealed class DefaultLinkGenerationTemplate : LinkGenerationTemplate internal sealed class DefaultLinkGenerationTemplate : LinkGenerationTemplate
{ {
public DefaultLinkGenerationTemplate(DefaultLinkGenerator linkGenerator, List<RouteEndpoint> endpoints) public DefaultLinkGenerationTemplate(DefaultLinkGenerator linkGenerator, List<RouteEndpoint> endpoints, LinkGenerationTemplateOptions options)
{ {
LinkGenerator = linkGenerator; LinkGenerator = linkGenerator;
Endpoints = endpoints; Endpoints = endpoints;
Options = options;
} }
public DefaultLinkGenerator LinkGenerator { get; } public DefaultLinkGenerator LinkGenerator { get; }
public List<RouteEndpoint> Endpoints { get; } public List<RouteEndpoint> Endpoints { get; }
public LinkGenerationTemplateOptions Options { get; }
public override string GetPath( public override string GetPath(
HttpContext httpContext, HttpContext httpContext,
object values, object values,
PathString? pathBase = default,
FragmentString fragment = default, FragmentString fragment = default,
LinkOptions options = null) LinkOptions options = default)
{ {
if (httpContext == null) if (httpContext == null)
{ {
@ -32,9 +36,9 @@ namespace Microsoft.AspNetCore.Routing
return LinkGenerator.GetPathByEndpoints( return LinkGenerator.GetPathByEndpoints(
Endpoints, Endpoints,
DefaultLinkGenerator.GetAmbientValues(httpContext),
new RouteValueDictionary(values), new RouteValueDictionary(values),
httpContext.Request.PathBase, GetAmbientValues(httpContext),
pathBase ?? httpContext.Request.PathBase,
fragment, fragment,
options); options);
} }
@ -43,22 +47,25 @@ namespace Microsoft.AspNetCore.Routing
object values, object values,
PathString pathBase = default, PathString pathBase = default,
FragmentString fragment = default, FragmentString fragment = default,
LinkOptions options = null) LinkOptions options = default)
{ {
return LinkGenerator.GetPathByEndpoints( return LinkGenerator.GetPathByEndpoints(
Endpoints, Endpoints,
ambientValues: null,
new RouteValueDictionary(values), new RouteValueDictionary(values),
pathBase, ambientValues: null,
fragment, pathBase: pathBase,
options); fragment: fragment,
options: options);
} }
public override string GetUri( public override string GetUri(
HttpContext httpContext, HttpContext httpContext,
object values, object values,
string scheme = default,
HostString? host = default,
PathString? pathBase = default,
FragmentString fragment = default, FragmentString fragment = default,
LinkOptions options = null) LinkOptions options = default)
{ {
if (httpContext == null) if (httpContext == null)
{ {
@ -67,11 +74,11 @@ namespace Microsoft.AspNetCore.Routing
return LinkGenerator.GetUriByEndpoints( return LinkGenerator.GetUriByEndpoints(
Endpoints, Endpoints,
DefaultLinkGenerator.GetAmbientValues(httpContext),
new RouteValueDictionary(values), new RouteValueDictionary(values),
httpContext.Request.Scheme, GetAmbientValues(httpContext),
httpContext.Request.Host, scheme ?? httpContext.Request.Scheme,
httpContext.Request.PathBase, host ?? httpContext.Request.Host,
pathBase ?? httpContext.Request.PathBase,
fragment, fragment,
options); options);
} }
@ -82,17 +89,32 @@ namespace Microsoft.AspNetCore.Routing
HostString host, HostString host,
PathString pathBase = default, PathString pathBase = default,
FragmentString fragment = default, FragmentString fragment = default,
LinkOptions options = null) LinkOptions options = default)
{ {
if (string.IsNullOrEmpty(scheme))
{
throw new ArgumentException("A scheme must be provided.", nameof(scheme));
}
if (!host.HasValue)
{
throw new ArgumentException("A host must be provided.", nameof(host));
}
return LinkGenerator.GetUriByEndpoints( return LinkGenerator.GetUriByEndpoints(
Endpoints, Endpoints,
ambientValues: null,
new RouteValueDictionary(values), new RouteValueDictionary(values),
scheme, ambientValues: null,
host, scheme: scheme,
pathBase, host: host,
fragment, pathBase: pathBase,
options); fragment: fragment,
options: options);
}
private RouteValueDictionary GetAmbientValues(HttpContext httpContext)
{
return (Options?.UseAmbientValues ?? false) ? DefaultLinkGenerator.GetAmbientValues(httpContext) : null;
} }
} }
} }

View File

@ -73,6 +73,8 @@ namespace Microsoft.AspNetCore.Routing
HttpContext httpContext, HttpContext httpContext,
TAddress address, TAddress address,
RouteValueDictionary values, RouteValueDictionary values,
RouteValueDictionary ambientValues = default,
PathString? pathBase = default,
FragmentString fragment = default, FragmentString fragment = default,
LinkOptions options = null) LinkOptions options = null)
{ {
@ -89,9 +91,9 @@ namespace Microsoft.AspNetCore.Routing
return GetPathByEndpoints( return GetPathByEndpoints(
endpoints, endpoints,
GetAmbientValues(httpContext),
values, values,
httpContext.Request.PathBase, ambientValues,
pathBase ?? httpContext.Request.PathBase,
fragment, fragment,
options); options);
} }
@ -111,17 +113,21 @@ namespace Microsoft.AspNetCore.Routing
return GetPathByEndpoints( return GetPathByEndpoints(
endpoints, endpoints,
ambientValues: null,
values, values,
pathBase, ambientValues: null,
fragment, pathBase: pathBase,
options); fragment: fragment,
options: options);
} }
public override string GetUriByAddress<TAddress>( public override string GetUriByAddress<TAddress>(
HttpContext httpContext, HttpContext httpContext,
TAddress address, TAddress address,
RouteValueDictionary values, RouteValueDictionary values,
RouteValueDictionary ambientValues = default,
string scheme = default,
HostString? host = default,
PathString? pathBase = default,
FragmentString fragment = default, FragmentString fragment = default,
LinkOptions options = null) LinkOptions options = null)
{ {
@ -138,11 +144,11 @@ namespace Microsoft.AspNetCore.Routing
return GetUriByEndpoints( return GetUriByEndpoints(
endpoints, endpoints,
GetAmbientValues(httpContext),
values, values,
httpContext.Request.Scheme, ambientValues,
httpContext.Request.Host, scheme ?? httpContext.Request.Scheme,
httpContext.Request.PathBase, host ?? httpContext.Request.Host,
pathBase ?? httpContext.Request.PathBase,
fragment, fragment,
options); options);
} }
@ -156,9 +162,14 @@ namespace Microsoft.AspNetCore.Routing
FragmentString fragment = default, FragmentString fragment = default,
LinkOptions options = null) LinkOptions options = null)
{ {
if (string.IsNullOrEmpty(scheme))
{
throw new ArgumentException("A scheme must be provided.", nameof(scheme));
}
if (!host.HasValue) if (!host.HasValue)
{ {
throw new ArgumentNullException(nameof(host)); throw new ArgumentException("A host must be provided.", nameof(host));
} }
var endpoints = GetEndpoints(address); var endpoints = GetEndpoints(address);
@ -169,16 +180,16 @@ namespace Microsoft.AspNetCore.Routing
return GetUriByEndpoints( return GetUriByEndpoints(
endpoints, endpoints,
ambientValues: null,
values, values,
scheme, ambientValues: null,
host, scheme: scheme,
pathBase, host: host,
fragment, pathBase: pathBase,
options); fragment: fragment,
options: options);
} }
public override LinkGenerationTemplate GetTemplateByAddress<TAddress>(TAddress address) public override LinkGenerationTemplate GetTemplateByAddress<TAddress>(TAddress address, LinkGenerationTemplateOptions options = default)
{ {
var endpoints = GetEndpoints(address); var endpoints = GetEndpoints(address);
if (endpoints.Count == 0) if (endpoints.Count == 0)
@ -186,7 +197,7 @@ namespace Microsoft.AspNetCore.Routing
return null; return null;
} }
return new DefaultLinkGenerationTemplate(this, endpoints); return new DefaultLinkGenerationTemplate(this, endpoints, options);
} }
private List<RouteEndpoint> GetEndpoints<TAddress>(TAddress address) private List<RouteEndpoint> GetEndpoints<TAddress>(TAddress address)
@ -209,8 +220,8 @@ namespace Microsoft.AspNetCore.Routing
// Also called from DefaultLinkGenerationTemplate // Also called from DefaultLinkGenerationTemplate
public string GetPathByEndpoints( public string GetPathByEndpoints(
List<RouteEndpoint> endpoints, List<RouteEndpoint> endpoints,
RouteValueDictionary ambientValues,
RouteValueDictionary values, RouteValueDictionary values,
RouteValueDictionary ambientValues,
PathString pathBase, PathString pathBase,
FragmentString fragment, FragmentString fragment,
LinkOptions options) LinkOptions options)
@ -220,11 +231,11 @@ namespace Microsoft.AspNetCore.Routing
var endpoint = endpoints[i]; var endpoint = endpoints[i];
if (TryProcessTemplate( if (TryProcessTemplate(
httpContext: null, httpContext: null,
endpoint, endpoint: endpoint,
values: values,
ambientValues: ambientValues, ambientValues: ambientValues,
values, options: options,
options, result: out var result))
out var result))
{ {
var uri = UriHelper.BuildRelative( var uri = UriHelper.BuildRelative(
pathBase, pathBase,
@ -243,8 +254,8 @@ namespace Microsoft.AspNetCore.Routing
// Also called from DefaultLinkGenerationTemplate // Also called from DefaultLinkGenerationTemplate
public string GetUriByEndpoints( public string GetUriByEndpoints(
List<RouteEndpoint> endpoints, List<RouteEndpoint> endpoints,
RouteValueDictionary ambientValues,
RouteValueDictionary values, RouteValueDictionary values,
RouteValueDictionary ambientValues,
string scheme, string scheme,
HostString host, HostString host,
PathString pathBase, PathString pathBase,
@ -256,11 +267,11 @@ namespace Microsoft.AspNetCore.Routing
var endpoint = endpoints[i]; var endpoint = endpoints[i];
if (TryProcessTemplate( if (TryProcessTemplate(
httpContext: null, httpContext: null,
endpoint, endpoint: endpoint,
values: values,
ambientValues: ambientValues, ambientValues: ambientValues,
values, options: options,
options, result: out var result))
out var result))
{ {
var uri = UriHelper.BuildAbsolute( var uri = UriHelper.BuildAbsolute(
scheme, scheme,
@ -323,19 +334,19 @@ namespace Microsoft.AspNetCore.Routing
internal bool TryProcessTemplate( internal bool TryProcessTemplate(
HttpContext httpContext, HttpContext httpContext,
RouteEndpoint endpoint, RouteEndpoint endpoint,
RouteValueDictionary values,
RouteValueDictionary ambientValues, RouteValueDictionary ambientValues,
RouteValueDictionary explicitValues,
LinkOptions options, LinkOptions options,
out (PathString path, QueryString query) result) out (PathString path, QueryString query) result)
{ {
var templateBinder = GetTemplateBinder(endpoint); var templateBinder = GetTemplateBinder(endpoint);
var templateValuesResult = templateBinder.GetValues(ambientValues, explicitValues); var templateValuesResult = templateBinder.GetValues(ambientValues, values);
if (templateValuesResult == null) if (templateValuesResult == null)
{ {
// We're missing one of the required values for this route. // We're missing one of the required values for this route.
result = default; result = default;
Log.TemplateFailedRequiredValues(_logger, endpoint, ambientValues, explicitValues); Log.TemplateFailedRequiredValues(_logger, endpoint, ambientValues, values);
return false; return false;
} }

View File

@ -11,6 +11,11 @@ namespace Microsoft.AspNetCore.Routing
/// </summary> /// </summary>
public static class LinkGeneratorEndpointNameAddressExtensions public static class LinkGeneratorEndpointNameAddressExtensions
{ {
private static readonly LinkGenerationTemplateOptions _templateOptions = new LinkGenerationTemplateOptions()
{
UseAmbientValues = false,
};
/// <summary> /// <summary>
/// Generates a URI with an absolute path based on the provided values. /// Generates a URI with an absolute path based on the provided values.
/// </summary> /// </summary>
@ -18,6 +23,9 @@ namespace Microsoft.AspNetCore.Routing
/// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param> /// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
/// <param name="endpointName">The endpoint name. Used to resolve endpoints.</param> /// <param name="endpointName">The endpoint name. Used to resolve endpoints.</param>
/// <param name="values">The route values. Used to expand parameters in the route template. Optional.</param> /// <param name="values">The route values. Used to expand parameters in the route template. Optional.</param>
/// <param name="pathBase">
/// An optional URI path base. Prepended to the path in the resulting URI. If not provided, the value of <see cref="HttpRequest.PathBase"/> will be used.
/// </param>
/// <param name="fragment">An optional URI fragment. Appended to the resulting URI.</param> /// <param name="fragment">An optional URI fragment. Appended to the resulting URI.</param>
/// <param name="options"> /// <param name="options">
/// An optional <see cref="LinkOptions"/>. Settings on provided object override the settings with matching /// An optional <see cref="LinkOptions"/>. Settings on provided object override the settings with matching
@ -29,6 +37,7 @@ namespace Microsoft.AspNetCore.Routing
HttpContext httpContext, HttpContext httpContext,
string endpointName, string endpointName,
object values, object values,
PathString? pathBase = default,
FragmentString fragment = default, FragmentString fragment = default,
LinkOptions options = default) LinkOptions options = default)
{ {
@ -37,12 +46,24 @@ namespace Microsoft.AspNetCore.Routing
throw new ArgumentNullException(nameof(generator)); throw new ArgumentNullException(nameof(generator));
} }
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (endpointName == null) if (endpointName == null)
{ {
throw new ArgumentNullException(nameof(endpointName)); throw new ArgumentNullException(nameof(endpointName));
} }
return generator.GetPathByAddress<string>(httpContext, endpointName, new RouteValueDictionary(values), fragment, options); return generator.GetPathByAddress<string>(
httpContext,
endpointName,
new RouteValueDictionary(values),
ambientValues: null,
pathBase,
fragment,
options);
} }
/// <summary> /// <summary>
@ -86,6 +107,15 @@ namespace Microsoft.AspNetCore.Routing
/// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param> /// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
/// <param name="endpointName">The endpoint name. Used to resolve endpoints.</param> /// <param name="endpointName">The endpoint name. Used to resolve endpoints.</param>
/// <param name="values">The route values. Used to expand parameters in the route template. Optional.</param> /// <param name="values">The route values. Used to expand parameters in the route template. Optional.</param>
/// <param name="scheme">
/// The URI scheme, applied to the resulting URI. Optional. If not provided, the value of <see cref="HttpRequest.Scheme"/> will be used.
/// </param>
/// <param name="host">
/// The URI host/authority, applied to the resulting URI. Optional. If not provided, the value <see cref="HttpRequest.Host"/> will be used.
/// </param>
/// <param name="pathBase">
/// An optional URI path base. Prepended to the path in the resulting URI. If not provided, the value of <see cref="HttpRequest.PathBase"/> will be used.
/// </param>
/// <param name="fragment">An optional URI fragment. Appended to the resulting URI.</param> /// <param name="fragment">An optional URI fragment. Appended to the resulting URI.</param>
/// <param name="options"> /// <param name="options">
/// An optional <see cref="LinkOptions"/>. Settings on provided object override the settings with matching /// An optional <see cref="LinkOptions"/>. Settings on provided object override the settings with matching
@ -97,6 +127,9 @@ namespace Microsoft.AspNetCore.Routing
HttpContext httpContext, HttpContext httpContext,
string endpointName, string endpointName,
object values, object values,
string scheme = default,
HostString? host = default,
PathString? pathBase = default,
FragmentString fragment = default, FragmentString fragment = default,
LinkOptions options = default) LinkOptions options = default)
{ {
@ -105,12 +138,26 @@ namespace Microsoft.AspNetCore.Routing
throw new ArgumentNullException(nameof(generator)); throw new ArgumentNullException(nameof(generator));
} }
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (endpointName == null) if (endpointName == null)
{ {
throw new ArgumentNullException(nameof(endpointName)); throw new ArgumentNullException(nameof(endpointName));
} }
return generator.GetUriByAddress<string>(httpContext, endpointName, new RouteValueDictionary(values), fragment, options); return generator.GetUriByAddress<string>(
httpContext,
endpointName,
new RouteValueDictionary(values),
ambientValues: null,
scheme,
host,
pathBase,
fragment,
options);
} }
/// <summary> /// <summary>
@ -147,7 +194,17 @@ namespace Microsoft.AspNetCore.Routing
{ {
throw new ArgumentNullException(nameof(endpointName)); throw new ArgumentNullException(nameof(endpointName));
} }
if (string.IsNullOrEmpty(scheme))
{
throw new ArgumentException("A scheme must be provided.", nameof(scheme));
}
if (!host.HasValue)
{
throw new ArgumentException("A host must be provided.", nameof(host));
}
return generator.GetUriByAddress<string>(endpointName, new RouteValueDictionary(values), scheme, host, pathBase, fragment, options); return generator.GetUriByAddress<string>(endpointName, new RouteValueDictionary(values), scheme, host, pathBase, fragment, options);
} }
@ -171,7 +228,7 @@ namespace Microsoft.AspNetCore.Routing
throw new ArgumentNullException(nameof(endpointName)); throw new ArgumentNullException(nameof(endpointName));
} }
return generator.GetTemplateByAddress<string>(endpointName); return generator.GetTemplateByAddress<string>(endpointName, _templateOptions);
} }
} }
} }

View File

@ -11,6 +11,11 @@ namespace Microsoft.AspNetCore.Routing
/// </summary> /// </summary>
public static class LinkGeneratorRouteValuesAddressExtensions public static class LinkGeneratorRouteValuesAddressExtensions
{ {
private static readonly LinkGenerationTemplateOptions _templateOptions = new LinkGenerationTemplateOptions()
{
UseAmbientValues = true,
};
/// <summary> /// <summary>
/// Generates a URI with an absolute path based on the provided values. /// Generates a URI with an absolute path based on the provided values.
/// </summary> /// </summary>
@ -18,6 +23,9 @@ namespace Microsoft.AspNetCore.Routing
/// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param> /// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
/// <param name="routeName">The route name. Used to resolve endpoints. Optional.</param> /// <param name="routeName">The route name. Used to resolve endpoints. Optional.</param>
/// <param name="values">The route values. Used to resolve endpoints and expand parameters in the route template. Optional.</param> /// <param name="values">The route values. Used to resolve endpoints and expand parameters in the route template. Optional.</param>
/// <param name="pathBase">
/// An optional URI path base. Prepended to the path in the resulting URI. If not provided, the value of <see cref="HttpRequest.PathBase"/> will be used.
/// </param>
/// <param name="fragment">An optional URI fragment. Appended to the resulting URI.</param> /// <param name="fragment">An optional URI fragment. Appended to the resulting URI.</param>
/// <param name="options"> /// <param name="options">
/// An optional <see cref="LinkOptions"/>. Settings on provided object override the settings with matching /// An optional <see cref="LinkOptions"/>. Settings on provided object override the settings with matching
@ -29,6 +37,7 @@ namespace Microsoft.AspNetCore.Routing
HttpContext httpContext, HttpContext httpContext,
string routeName, string routeName,
object values, object values,
PathString? pathBase = default,
FragmentString fragment = default, FragmentString fragment = default,
LinkOptions options = default) LinkOptions options = default)
{ {
@ -37,8 +46,20 @@ namespace Microsoft.AspNetCore.Routing
throw new ArgumentNullException(nameof(generator)); throw new ArgumentNullException(nameof(generator));
} }
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
var address = CreateAddress(httpContext, routeName, values); var address = CreateAddress(httpContext, routeName, values);
return generator.GetPathByAddress<RouteValuesAddress>(httpContext, address, address.ExplicitValues, fragment, options); return generator.GetPathByAddress<RouteValuesAddress>(
httpContext,
address,
address.ExplicitValues,
address.AmbientValues,
pathBase,
fragment,
options);
} }
/// <summary> /// <summary>
@ -78,6 +99,15 @@ namespace Microsoft.AspNetCore.Routing
/// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param> /// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
/// <param name="routeName">The route name. Used to resolve endpoints. Optional.</param> /// <param name="routeName">The route name. Used to resolve endpoints. Optional.</param>
/// <param name="values">The route values. Used to resolve endpoints and expand parameters in the route template. Optional.</param> /// <param name="values">The route values. Used to resolve endpoints and expand parameters in the route template. Optional.</param>
/// <param name="scheme">
/// The URI scheme, applied to the resulting URI. Optional. If not provided, the value of <see cref="HttpRequest.Scheme"/> will be used.
/// </param>
/// <param name="host">
/// The URI host/authority, applied to the resulting URI. Optional. If not provided, the value <see cref="HttpRequest.Host"/> will be used.
/// </param>
/// <param name="pathBase">
/// An optional URI path base. Prepended to the path in the resulting URI. If not provided, the value of <see cref="HttpRequest.PathBase"/> will be used.
/// </param>
/// <param name="fragment">An optional URI fragment. Appended to the resulting URI.</param> /// <param name="fragment">An optional URI fragment. Appended to the resulting URI.</param>
/// <param name="options"> /// <param name="options">
/// An optional <see cref="LinkOptions"/>. Settings on provided object override the settings with matching /// An optional <see cref="LinkOptions"/>. Settings on provided object override the settings with matching
@ -89,6 +119,9 @@ namespace Microsoft.AspNetCore.Routing
HttpContext httpContext, HttpContext httpContext,
string routeName, string routeName,
object values, object values,
string scheme = default,
HostString? host = default,
PathString? pathBase = default,
FragmentString fragment = default, FragmentString fragment = default,
LinkOptions options = default) LinkOptions options = default)
{ {
@ -97,8 +130,22 @@ namespace Microsoft.AspNetCore.Routing
throw new ArgumentNullException(nameof(generator)); throw new ArgumentNullException(nameof(generator));
} }
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
var address = CreateAddress(httpContext: null, routeName, values); var address = CreateAddress(httpContext: null, routeName, values);
return generator.GetUriByAddress<RouteValuesAddress>(httpContext, address, address.ExplicitValues, fragment, options); return generator.GetUriByAddress<RouteValuesAddress>(
httpContext,
address,
address.ExplicitValues,
address.AmbientValues,
scheme,
host,
pathBase,
fragment,
options);
} }
/// <summary> /// <summary>
@ -155,9 +202,9 @@ namespace Microsoft.AspNetCore.Routing
} }
var address = CreateAddress(httpContext: null, routeName, values); var address = CreateAddress(httpContext: null, routeName, values);
return generator.GetTemplateByAddress<RouteValuesAddress>(address); return generator.GetTemplateByAddress<RouteValuesAddress>(address, _templateOptions);
} }
private static RouteValuesAddress CreateAddress(HttpContext httpContext, string routeName, object values) private static RouteValuesAddress CreateAddress(HttpContext httpContext, string routeName, object values)
{ {
return new RouteValuesAddress() return new RouteValuesAddress()

View File

@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Routing
var endpoint2 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id?}"); var endpoint2 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id?}");
var linkGenerator = CreateLinkGenerator(); var linkGenerator = CreateLinkGenerator();
var template = new DefaultLinkGenerationTemplate(linkGenerator, new List<RouteEndpoint>() { endpoint1, endpoint2, }); var template = new DefaultLinkGenerationTemplate(linkGenerator, new List<RouteEndpoint>() { endpoint1, endpoint2, }, options: null);
// Act // Act
var path = template.GetPath( var path = template.GetPath(
@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.Routing
var endpoint2 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id?}"); var endpoint2 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id?}");
var linkGenerator = CreateLinkGenerator(); var linkGenerator = CreateLinkGenerator();
var template = new DefaultLinkGenerationTemplate(linkGenerator, new List<RouteEndpoint>() { endpoint1, endpoint2, }); var template = new DefaultLinkGenerationTemplate(linkGenerator, new List<RouteEndpoint>() { endpoint1, endpoint2, }, options: null);
var httpContext = CreateHttpContext(); var httpContext = CreateHttpContext();
httpContext.Request.PathBase = new PathString("/Foo/Bar?encodeme?"); httpContext.Request.PathBase = new PathString("/Foo/Bar?encodeme?");
@ -52,8 +52,8 @@ namespace Microsoft.AspNetCore.Routing
var path = template.GetPath( var path = template.GetPath(
httpContext, httpContext,
values: new RouteValueDictionary(new { controller = "Home", action = "In?dex", query = "some?query" }), values: new RouteValueDictionary(new { controller = "Home", action = "In?dex", query = "some?query" }),
new FragmentString("#Fragment?"), fragment: new FragmentString("#Fragment?"),
new LinkOptions() { AppendTrailingSlash = true, }); options: new LinkOptions() { AppendTrailingSlash = true, });
// Assert // Assert
Assert.Equal("/Foo/Bar%3Fencodeme%3F/Home/In%3Fdex/?query=some%3Fquery#Fragment?", path); Assert.Equal("/Foo/Bar%3Fencodeme%3F/Home/In%3Fdex/?query=some%3Fquery#Fragment?", path);
@ -67,7 +67,7 @@ namespace Microsoft.AspNetCore.Routing
var endpoint2 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id?}"); var endpoint2 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id?}");
var linkGenerator = CreateLinkGenerator(); var linkGenerator = CreateLinkGenerator();
var template = new DefaultLinkGenerationTemplate(linkGenerator, new List<RouteEndpoint>() { endpoint1, endpoint2, }); var template = new DefaultLinkGenerationTemplate(linkGenerator, new List<RouteEndpoint>() { endpoint1, endpoint2, }, options: null);
// Act // Act
var path = template.GetUri( var path = template.GetUri(
@ -90,7 +90,7 @@ namespace Microsoft.AspNetCore.Routing
var endpoint2 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id?}"); var endpoint2 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id?}");
var linkGenerator = CreateLinkGenerator(); var linkGenerator = CreateLinkGenerator();
var template = new DefaultLinkGenerationTemplate(linkGenerator, new List<RouteEndpoint>() { endpoint1, endpoint2, }); var template = new DefaultLinkGenerationTemplate(linkGenerator, new List<RouteEndpoint>() { endpoint1, endpoint2, }, options: null);
var httpContext = CreateHttpContext(); var httpContext = CreateHttpContext();
httpContext.Request.Scheme = "http"; httpContext.Request.Scheme = "http";
@ -101,22 +101,25 @@ namespace Microsoft.AspNetCore.Routing
var uri = template.GetUri( var uri = template.GetUri(
httpContext, httpContext,
values: new RouteValueDictionary(new { controller = "Home", action = "In?dex", query = "some?query" }), values: new RouteValueDictionary(new { controller = "Home", action = "In?dex", query = "some?query" }),
new FragmentString("#Fragment?"), fragment: new FragmentString("#Fragment?"),
new LinkOptions() { AppendTrailingSlash = true, }); options: new LinkOptions() { AppendTrailingSlash = true, });
// Assert // Assert
Assert.Equal("http://example.com/Foo/Bar%3Fencodeme%3F/Home/In%3Fdex/?query=some%3Fquery#Fragment?", uri); Assert.Equal("http://example.com/Foo/Bar%3Fencodeme%3F/Home/In%3Fdex/?query=some%3Fquery#Fragment?", uri);
} }
[Fact] [Fact]
public void GetPath_WithHttpContext_IncludesAmbientValues() public void GetPath_WithHttpContext_IncludesAmbientValues_WhenUseAmbientValuesIsTrue()
{ {
// Arrange // Arrange
var endpoint1 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id}"); var endpoint1 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id}");
var endpoint2 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id?}"); var endpoint2 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id?}");
var linkGenerator = CreateLinkGenerator(); var linkGenerator = CreateLinkGenerator();
var template = new DefaultLinkGenerationTemplate(linkGenerator, new List<RouteEndpoint>() { endpoint1, endpoint2, }); var template = new DefaultLinkGenerationTemplate(linkGenerator, new List<RouteEndpoint>() { endpoint1, endpoint2, }, options: new LinkGenerationTemplateOptions()
{
UseAmbientValues = true,
});
var httpContext = CreateHttpContext(new { controller = "Home", }); var httpContext = CreateHttpContext(new { controller = "Home", });
httpContext.Request.Scheme = "http"; httpContext.Request.Scheme = "http";
@ -130,14 +133,41 @@ namespace Microsoft.AspNetCore.Routing
} }
[Fact] [Fact]
public void GetUri_WithHttpContext_IncludesAmbientValues() public void GetPath_WithHttpContext_ExcludesAmbientValues_WhenUseAmbientValuesIsFalse()
{ {
// Arrange // Arrange
var endpoint1 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id}"); var endpoint1 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id}");
var endpoint2 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id?}"); var endpoint2 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id?}");
var linkGenerator = CreateLinkGenerator(); var linkGenerator = CreateLinkGenerator();
var template = new DefaultLinkGenerationTemplate(linkGenerator, new List<RouteEndpoint>() { endpoint1, endpoint2, }); var template = new DefaultLinkGenerationTemplate(linkGenerator, new List<RouteEndpoint>() { endpoint1, endpoint2, }, options: new LinkGenerationTemplateOptions()
{
UseAmbientValues = false,
});
var httpContext = CreateHttpContext(new { controller = "Home", });
httpContext.Request.Scheme = "http";
httpContext.Request.Host = new HostString("example.com");
// Act
var uri = template.GetPath(httpContext, values: new RouteValueDictionary(new { action = "Index", }));
// Assert
Assert.Null(uri);
}
[Fact]
public void GetUri_WithHttpContext_IncludesAmbientValues_WhenUseAmbientValuesIsTrue()
{
// Arrange
var endpoint1 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id}");
var endpoint2 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id?}");
var linkGenerator = CreateLinkGenerator();
var template = new DefaultLinkGenerationTemplate(linkGenerator, new List<RouteEndpoint>() { endpoint1, endpoint2, }, options: new LinkGenerationTemplateOptions()
{
UseAmbientValues = true,
});
var httpContext = CreateHttpContext(new { controller = "Home", }); var httpContext = CreateHttpContext(new { controller = "Home", });
httpContext.Request.Scheme = "http"; httpContext.Request.Scheme = "http";
@ -149,5 +179,29 @@ namespace Microsoft.AspNetCore.Routing
// Assert // Assert
Assert.Equal("http://example.com/Home/Index", uri); Assert.Equal("http://example.com/Home/Index", uri);
} }
[Fact]
public void GetUri_WithHttpContext_ExcludesAmbientValues_WhenUseAmbientValuesIsFalse()
{
// Arrange
var endpoint1 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id}");
var endpoint2 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id?}");
var linkGenerator = CreateLinkGenerator();
var template = new DefaultLinkGenerationTemplate(linkGenerator, new List<RouteEndpoint>() { endpoint1, endpoint2, }, options: new LinkGenerationTemplateOptions()
{
UseAmbientValues = false,
});
var httpContext = CreateHttpContext(new { controller = "Home", });
httpContext.Request.Scheme = "http";
httpContext.Request.Host = new HostString("example.com");
// Act
var uri = template.GetUri(httpContext, values: new { action = "Index", });
// Assert
Assert.Null(uri);
}
} }
} }

View File

@ -25,10 +25,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: null, httpContext: null,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { p1 = "Home", p3 = "bar", }),
ambientValues: null, ambientValues: null,
explicitValues: new RouteValueDictionary(new { p1 = "Home", p3 = "bar", }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -50,10 +50,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { path = routeValue, }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { path = routeValue, }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -82,10 +82,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { path = routeValue, }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { path = routeValue, }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -105,10 +105,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { path = "a/b b1/c c1" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { path = "a/b b1/c c1" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -128,10 +128,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { name = "name with %special #characters" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { name = "name with %special #characters" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -151,10 +151,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { color = new List<string> { "red", "green", "blue" } }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { color = new List<string> { "red", "green", "blue" } }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -174,10 +174,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { items = new List<int> { 10, 20, 30 } }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { items = new List<int> { 10, 20, 30 } }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -197,10 +197,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { color = new List<string> { } }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { color = new List<string> { } }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -220,10 +220,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { page = 1, color = new List<string> { "red", "green", "blue" }, message = "textfortest" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { page = 1, color = new List<string> { "red", "green", "blue" }, message = "textfortest" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -243,10 +243,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "Index" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "Index" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -266,10 +266,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "Index" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "Index" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -290,10 +290,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { id = "18" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { id = "18" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -314,10 +314,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { id = "18" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { id = "18" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -341,10 +341,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), values: new RouteValueDictionary(new { action = "П" }),
explicitValues: new RouteValueDictionary(new { action = "П" }), // Cryillic uppercase Pe ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), // Cryillic uppercase Pe
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -371,10 +371,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "Index", ShowStatus = "True", INFO = "DETAILED" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "Index", ShowStatus = "True", INFO = "DETAILED" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -396,10 +396,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "Index" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "Index" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -421,10 +421,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "Index", ShowStatus = "True", INFO = "DETAILED" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "Index", ShowStatus = "True", INFO = "DETAILED" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -446,13 +446,13 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "InDex" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "InDex" }),
options: new LinkOptions options: new LinkOptions
{ {
LowercaseUrls = false LowercaseUrls = false
}, },
out var result); result: out var result);
// Assert // Assert
@ -475,13 +475,13 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "InDex" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "InDex" }),
options: new LinkOptions() options: new LinkOptions()
{ {
LowercaseUrls = true LowercaseUrls = true
}, },
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -503,14 +503,14 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "Index", ShowStatus = "True", INFO = "DETAILED" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "Index", ShowStatus = "True", INFO = "DETAILED" }),
options: new LinkOptions options: new LinkOptions
{ {
LowercaseUrls = false, LowercaseUrls = false,
LowercaseQueryStrings = false LowercaseQueryStrings = false
}, },
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -532,14 +532,14 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "Index", ShowStatus = "True", INFO = "DETAILED" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "Index", ShowStatus = "True", INFO = "DETAILED" }),
options: new LinkOptions() options: new LinkOptions()
{ {
LowercaseUrls = true, LowercaseUrls = true,
LowercaseQueryStrings = true, LowercaseQueryStrings = true,
}, },
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -561,10 +561,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "Index" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "Index" }),
options: new LinkOptions() { AppendTrailingSlash = true, }, options: new LinkOptions() { AppendTrailingSlash = true, },
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -587,10 +587,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { p1 = "abcd" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { p1 = "abcd" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.False(success); Assert.False(success);
@ -611,10 +611,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { p1 = "hello", p2 = "1234" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { p1 = "hello", p2 = "1234" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -637,10 +637,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { p1 = "abcd" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { p1 = "abcd" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.False(success); Assert.False(success);
@ -661,10 +661,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { p1 = "hello", p2 = "1234" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { p1 = "hello", p2 = "1234" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -698,10 +698,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { p1 = "hello", p2 = "1234" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { p1 = "hello", p2 = "1234" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -733,10 +733,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "Store" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "Store" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -766,10 +766,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "Store" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "Store" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -798,10 +798,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { controller = "Shopping" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { controller = "Shopping" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -832,10 +832,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "Store", thirdthing = "13" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "Store", thirdthing = "13" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -862,10 +862,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "Index", controller = "Home", id = 4 }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "Index", controller = "Home", id = 4 }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -888,10 +888,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "Index", controller = "Home", id = "not-an-integer" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "Index", controller = "Home", id = "not-an-integer" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.False(success); Assert.False(success);
@ -914,10 +914,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "Index", controller = "Home", id = 98 }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "Index", controller = "Home", id = 98 }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -940,10 +940,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "Index", controller = "Home" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "Index", controller = "Home" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -966,10 +966,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "Index", controller = "Home", id = "not-an-integer" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "Index", controller = "Home", id = "not-an-integer" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.False(success); Assert.False(success);
@ -992,10 +992,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "Index", controller = "Home", id = 14 }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "Index", controller = "Home", id = 14 }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -1020,10 +1020,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "Index", controller = "Home", id = 50 }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "Index", controller = "Home", id = 50 }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.False(success); Assert.False(success);
@ -1045,10 +1045,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "Index", controller = "Home", name = "products" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "Index", controller = "Home", name = "products" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -1068,10 +1068,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "Index", controller = "Home", name = "products" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "Index", controller = "Home", name = "products" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -1091,10 +1091,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "Index", controller = "Home" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "Index", controller = "Home" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -1116,10 +1116,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "Index", controller = "Home", name = "products" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "Index", controller = "Home", name = "products" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -1141,10 +1141,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "Index", controller = "Home" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "Index", controller = "Home" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -1164,10 +1164,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "Index", controller = "Home", name = "products", format = "json" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "Index", controller = "Home", name = "products", format = "json" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -1188,10 +1188,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "Index", controller = "Home", name = "products" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "Index", controller = "Home", name = "products" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -1211,10 +1211,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "Index", controller = "Home" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "Index", controller = "Home" }),
options: null, options: null,
out var result); result: out var result);
Assert.True(success); Assert.True(success);
@ -1234,10 +1234,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { action = "Index", controller = "Home" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { action = "Index", controller = "Home" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -1257,10 +1257,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -1280,10 +1280,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -1303,10 +1303,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -1407,10 +1407,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(explicitValues),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(explicitValues),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -1435,10 +1435,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { c = "Products", a = "Edit" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { c = "Products", a = "Edit" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.True(success); Assert.True(success);
@ -1463,10 +1463,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(new { c = "Products", a = "List" }),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(new { c = "Products", a = "List" }),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.False(success); Assert.False(success);
@ -1571,10 +1571,10 @@ namespace Microsoft.AspNetCore.Routing
var success = linkGenerator.TryProcessTemplate( var success = linkGenerator.TryProcessTemplate(
httpContext: httpContext, httpContext: httpContext,
endpoint: endpoint, endpoint: endpoint,
values: new RouteValueDictionary(explicitValues),
ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext), ambientValues: DefaultLinkGenerator.GetAmbientValues(httpContext),
explicitValues: new RouteValueDictionary(explicitValues),
options: null, options: null,
out var result); result: out var result);
// Assert // Assert
Assert.False(success); Assert.False(success);

View File

@ -370,7 +370,7 @@ namespace Microsoft.AspNetCore.Routing
httpContext, httpContext,
1, 1,
values: new RouteValueDictionary(new { controller = "Home", action = "In?dex", query = "some?query" }), values: new RouteValueDictionary(new { controller = "Home", action = "In?dex", query = "some?query" }),
new FragmentString("#Fragment?")); fragment: new FragmentString("#Fragment?"));
// Assert // Assert
Assert.Equal("/Foo/Bar%3Fencodeme%3F/Home/In%3Fdex?query=some%3Fquery#Fragment?", path); Assert.Equal("/Foo/Bar%3Fencodeme%3F/Home/In%3Fdex?query=some%3Fquery#Fragment?", path);
@ -419,7 +419,7 @@ namespace Microsoft.AspNetCore.Routing
httpContext, httpContext,
1, 1,
values: new RouteValueDictionary(new { controller = "Home", action = "In?dex", query = "some?query" }), values: new RouteValueDictionary(new { controller = "Home", action = "In?dex", query = "some?query" }),
new FragmentString("#Fragment?")); fragment: new FragmentString("#Fragment?"));
// Assert // Assert
Assert.Equal("http://example.com/Foo/Bar%3Fencodeme%3F/Home/In%3Fdex?query=some%3Fquery#Fragment?", uri); Assert.Equal("http://example.com/Foo/Bar%3Fencodeme%3F/Home/In%3Fdex?query=some%3Fquery#Fragment?", uri);
@ -434,12 +434,16 @@ namespace Microsoft.AspNetCore.Routing
var linkGenerator = CreateLinkGenerator(endpoint1, endpoint2); var linkGenerator = CreateLinkGenerator(endpoint1, endpoint2);
var httpContext = CreateHttpContext(new { controller = "Home", }); var httpContext = CreateHttpContext();
httpContext.Request.Scheme = "http"; httpContext.Request.Scheme = "http";
httpContext.Request.Host = new HostString("example.com"); httpContext.Request.Host = new HostString("example.com");
// Act // Act
var uri = linkGenerator.GetPathByAddress(httpContext, 1, values: new RouteValueDictionary(new { action = "Index", })); var uri = linkGenerator.GetPathByAddress(
httpContext,
1,
values: new RouteValueDictionary(new { action = "Index", }),
ambientValues: new RouteValueDictionary(new { controller = "Home", }));
// Assert // Assert
Assert.Equal("/Home/Index", uri); Assert.Equal("/Home/Index", uri);
@ -454,17 +458,71 @@ namespace Microsoft.AspNetCore.Routing
var linkGenerator = CreateLinkGenerator(endpoint1, endpoint2); var linkGenerator = CreateLinkGenerator(endpoint1, endpoint2);
var httpContext = CreateHttpContext(new { controller = "Home", }); var httpContext = CreateHttpContext();
httpContext.Request.Scheme = "http"; httpContext.Request.Scheme = "http";
httpContext.Request.Host = new HostString("example.com"); httpContext.Request.Host = new HostString("example.com");
// Act // Act
var uri = linkGenerator.GetUriByAddress(httpContext, 1, values: new RouteValueDictionary(new { action = "Index", })); var uri = linkGenerator.GetUriByAddress(
httpContext,
1,
values: new RouteValueDictionary(new { action = "Index", }),
ambientValues: new RouteValueDictionary(new { controller = "Home", }));
// Assert // Assert
Assert.Equal("http://example.com/Home/Index", uri); Assert.Equal("http://example.com/Home/Index", uri);
} }
[Fact]
public void GetPathByAddress_WithHttpContext_CanOverrideUriParts()
{
// Arrange
var endpoint1 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id}", metadata: new object[] { new IntMetadata(1), });
var endpoint2 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id?}", metadata: new object[] { new IntMetadata(1), });
var linkGenerator = CreateLinkGenerator(endpoint1, endpoint2);
var httpContext = CreateHttpContext();
httpContext.Request.PathBase = "/Foo";
// Act
var uri = linkGenerator.GetPathByAddress(
httpContext,
1,
values: new RouteValueDictionary(new { action = "Index", controller= "Home", }),
pathBase: "/");
// Assert
Assert.Equal("/Home/Index", uri);
}
[Fact]
public void GetUriByAddress_WithHttpContext_CanOverrideUriParts()
{
// Arrange
var endpoint1 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id}", metadata: new object[] { new IntMetadata(1), });
var endpoint2 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id?}", metadata: new object[] { new IntMetadata(1), });
var linkGenerator = CreateLinkGenerator(endpoint1, endpoint2);
var httpContext = CreateHttpContext();
httpContext.Request.Scheme = "http";
httpContext.Request.Host = new HostString("example.com");
httpContext.Request.PathBase = "/Foo";
// Act
var uri = linkGenerator.GetUriByAddress(
httpContext,
1,
values: new RouteValueDictionary(new { action = "Index", controller = "Home", }),
scheme: "ftp",
host: new HostString("example.com:5000"),
pathBase: "/");
// Assert
Assert.Equal("ftp://example.com:5000/Home/Index", uri);
}
[Fact] [Fact]
public void GetTemplateByAddress_WithNoMatch_ReturnsNull() public void GetTemplateByAddress_WithNoMatch_ReturnsNull()
{ {

View File

@ -3,6 +3,7 @@
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Routing namespace Microsoft.AspNetCore.Routing
@ -16,6 +17,37 @@ namespace Microsoft.AspNetCore.Routing
// Does not cover the EndpointNameEndpointFinder in detail. see EndpointNameEndpointFinderTest // Does not cover the EndpointNameEndpointFinder in detail. see EndpointNameEndpointFinderTest
public class LinkGeneratorEndpointNameExtensionsTest : LinkGeneratorTestBase public class LinkGeneratorEndpointNameExtensionsTest : LinkGeneratorTestBase
{ {
[Fact]
public void GetPathByName_WithHttpContext_DoesNotUseAmbientValues()
{
// Arrange
var endpoint1 = EndpointFactory.CreateRouteEndpoint("some-endpoint/{p}", metadata: new[] { new EndpointNameMetadata("name1"), });
var endpoint2 = EndpointFactory.CreateRouteEndpoint("some#-other-endpoint/{p}", metadata: new[] { new EndpointNameMetadata("name2"), });
var linkGenerator = CreateLinkGenerator(endpoint1, endpoint2);
var feature = new EndpointFeature()
{
RouteValues = new RouteValueDictionary(new { p = "5", })
};
var httpContext = CreateHttpContext();
httpContext.Features.Set<IRouteValuesFeature>(feature);
httpContext.Request.PathBase = new PathString("/Foo/Bar?encodeme?");
var values = new { query = "some?query", };
// Act
var path = linkGenerator.GetPathByName(
httpContext,
endpointName: "name2",
values,
fragment: new FragmentString("#Fragment?"),
options: new LinkOptions() { AppendTrailingSlash = true, });
// Assert
Assert.Null(path);
}
[Fact] [Fact]
public void GetPathByName_WithoutHttpContext_WithPathBaseAndFragment() public void GetPathByName_WithoutHttpContext_WithPathBaseAndFragment()
{ {
@ -58,8 +90,8 @@ namespace Microsoft.AspNetCore.Routing
httpContext, httpContext,
endpointName: "name2", endpointName: "name2",
values, values,
new FragmentString("#Fragment?"), fragment: new FragmentString("#Fragment?"),
new LinkOptions() { AppendTrailingSlash = true, }); options: new LinkOptions() { AppendTrailingSlash = true, });
// Assert // Assert
Assert.Equal("/Foo/Bar%3Fencodeme%3F/some%23-other-endpoint/In%3Fdex/?query=some%3Fquery#Fragment?", path); Assert.Equal("/Foo/Bar%3Fencodeme%3F/some%23-other-endpoint/In%3Fdex/?query=some%3Fquery#Fragment?", path);
@ -111,8 +143,8 @@ namespace Microsoft.AspNetCore.Routing
httpContext, httpContext,
endpointName: "name2", endpointName: "name2",
values, values,
new FragmentString("#Fragment?"), fragment: new FragmentString("#Fragment?"),
new LinkOptions() { AppendTrailingSlash = true, }); options: new LinkOptions() { AppendTrailingSlash = true, });
// Assert // Assert
Assert.Equal("http://example.com/Foo/Bar%3Fencodeme%3F/some%23-other-endpoint/In%3Fdex/?query=some%3Fquery#Fragment?", uri); Assert.Equal("http://example.com/Foo/Bar%3Fencodeme%3F/some%23-other-endpoint/In%3Fdex/?query=some%3Fquery#Fragment?", uri);

View File

@ -3,6 +3,7 @@
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Routing namespace Microsoft.AspNetCore.Routing
@ -16,6 +17,41 @@ namespace Microsoft.AspNetCore.Routing
// Does not cover the RouteValueBasedEndpointFinder in detail. see RouteValueBasedEndpointFinderTest // Does not cover the RouteValueBasedEndpointFinder in detail. see RouteValueBasedEndpointFinderTest
public class LinkGeneratorRouteValuesAddressExtensionsTest : LinkGeneratorTestBase public class LinkGeneratorRouteValuesAddressExtensionsTest : LinkGeneratorTestBase
{ {
[Fact]
public void GetPathByRouteValues_WithHttpContext_UsesAmbientValues()
{
// Arrange
var endpoint1 = EndpointFactory.CreateRouteEndpoint(
"Home/Index/{id}",
defaults: new { controller = "Home", action = "Index", },
metadata: new[] { new RouteValuesAddressMetadata(routeName: null, new RouteValueDictionary(new { controller = "Home", action = "Index", })) });
var endpoint2 = EndpointFactory.CreateRouteEndpoint(
"Home/Index/{id?}",
defaults: new { controller = "Home", action = "Index", },
metadata: new[] { new RouteValuesAddressMetadata(routeName: null, new RouteValueDictionary(new { controller = "Home", action = "Index", })) });
var linkGenerator = CreateLinkGenerator(endpoint1, endpoint2);
var feature = new EndpointFeature()
{
RouteValues = new RouteValueDictionary(new { action = "Index", })
};
var httpContext = CreateHttpContext();
httpContext.Features.Set<IRouteValuesFeature>(feature);
httpContext.Request.PathBase = new PathString("/Foo/Bar?encodeme?");
// Act
var path = linkGenerator.GetPathByRouteValues(
httpContext,
routeName: null,
values: new RouteValueDictionary(new { controller = "Home", query = "some?query" }),
fragment: new FragmentString("#Fragment?"),
options: new LinkOptions() { AppendTrailingSlash = true, });
// Assert
Assert.Equal("/Foo/Bar%3Fencodeme%3F/Home/Index/?query=some%3Fquery#Fragment?", path);
}
[Fact] [Fact]
public void GetPathByRouteValues_WithoutHttpContext_WithPathBaseAndFragment() public void GetPathByRouteValues_WithoutHttpContext_WithPathBaseAndFragment()
{ {
@ -66,8 +102,8 @@ namespace Microsoft.AspNetCore.Routing
httpContext, httpContext,
routeName: null, routeName: null,
values: new RouteValueDictionary(new { controller = "Home", action = "Index", query = "some?query" }), values: new RouteValueDictionary(new { controller = "Home", action = "Index", query = "some?query" }),
new FragmentString("#Fragment?"), fragment: new FragmentString("#Fragment?"),
new LinkOptions() { AppendTrailingSlash = true, }); options: new LinkOptions() { AppendTrailingSlash = true, });
// Assert // Assert
Assert.Equal("/Foo/Bar%3Fencodeme%3F/Home/Index/?query=some%3Fquery#Fragment?", path); Assert.Equal("/Foo/Bar%3Fencodeme%3F/Home/Index/?query=some%3Fquery#Fragment?", path);
@ -127,8 +163,8 @@ namespace Microsoft.AspNetCore.Routing
httpContext, httpContext,
routeName: null, routeName: null,
values: new RouteValueDictionary(new { controller = "Home", action = "Index", query = "some?query" }), values: new RouteValueDictionary(new { controller = "Home", action = "Index", query = "some?query" }),
new FragmentString("#Fragment?"), fragment: new FragmentString("#Fragment?"),
new LinkOptions() { AppendTrailingSlash = true, }); options: new LinkOptions() { AppendTrailingSlash = true, });
// Assert // Assert
Assert.Equal("http://example.com/Foo/Bar%3Fencodeme%3F/Home/Index/?query=some%3Fquery#Fragment?", uri); Assert.Equal("http://example.com/Foo/Bar%3Fencodeme%3F/Home/Index/?query=some%3Fquery#Fragment?", uri);