Merge pull request #887 from dotnet-maestro-bot/merge/release/2.2-to-master
[automated] Merge branch 'release/2.2' => 'master'
This commit is contained in:
commit
74336f10c7
|
|
@ -1,126 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a contract to generate a URL from a template.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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"/>
|
||||
/// will be bound to the endpoints matching the address that was originally provided.
|
||||
/// </remarks>
|
||||
public abstract class LinkGenerationTemplate
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates a URI with an absolute path based on the provided values.
|
||||
/// </summary>
|
||||
/// <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="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="options">
|
||||
/// An optional <see cref="LinkOptions"/>. Settings on provided object override the settings with matching
|
||||
/// names from <c>RouteOptions</c>.
|
||||
/// </param>
|
||||
/// <returns>A URI with an absolute path, or <c>null</c>.</returns>
|
||||
public abstract string GetPath(
|
||||
HttpContext httpContext,
|
||||
object values,
|
||||
PathString? pathBase = default,
|
||||
FragmentString fragment = default,
|
||||
LinkOptions options = default);
|
||||
|
||||
/// <summary>
|
||||
/// Generates a URI with an absolute path based on the provided values.
|
||||
/// </summary>
|
||||
/// <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.</param>
|
||||
/// <param name="fragment">An optional URI fragment. Appended to the resulting URI.</param>
|
||||
/// <param name="options">
|
||||
/// An optional <see cref="LinkOptions"/>. Settings on provided object override the settings with matching
|
||||
/// names from <c>RouteOptions</c>.
|
||||
/// </param>
|
||||
/// <returns>A URI with an absolute path, or <c>null</c>.</returns>
|
||||
public abstract string GetPath(
|
||||
object values,
|
||||
PathString pathBase = default,
|
||||
FragmentString fragment = default,
|
||||
LinkOptions options = default);
|
||||
|
||||
/// <summary>
|
||||
/// Generates an absolute URI based on the provided values.
|
||||
/// </summary>
|
||||
/// <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="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.
|
||||
/// See the remarks section for details about the security implications of the <paramref name="host"/>.
|
||||
/// </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="options">
|
||||
/// An optional <see cref="LinkOptions"/>. Settings on provided object override the settings with matching
|
||||
/// names from <c>RouteOptions</c>.
|
||||
/// </param>
|
||||
/// <returns>A URI with an absolute path, or <c>null</c>.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The value of <paramref name="host" /> should be a trusted value. Relying on the value of the current request
|
||||
/// can allow untrusted input to influence the resulting URI unless the <c>Host</c> header has been validated.
|
||||
/// See the deployment documentation for instructions on how to properly validate the <c>Host</c> header in
|
||||
/// your deployment environment.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public abstract string GetUri(
|
||||
HttpContext httpContext,
|
||||
object values,
|
||||
string scheme = default,
|
||||
HostString? host = default,
|
||||
PathString? pathBase = default,
|
||||
FragmentString fragment = default,
|
||||
LinkOptions options = default);
|
||||
|
||||
/// <summary>
|
||||
/// Generates an absolute URI based on the provided values.
|
||||
/// </summary>
|
||||
/// <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.</param>
|
||||
/// <param name="host">
|
||||
/// The URI host/authority, applied to the resulting URI.
|
||||
/// See the remarks section for details about the security implications of the <paramref name="host"/>.
|
||||
/// </param>
|
||||
/// <param name="pathBase">An optional URI path base. Prepended to the path in the resulting URI.</param>
|
||||
/// <param name="fragment">An optional URI fragment. Appended to the resulting URI.</param>
|
||||
/// <param name="options">
|
||||
/// An optional <see cref="LinkOptions"/>. Settings on provided object override the settings with matching
|
||||
/// names from <c>RouteOptions</c>.
|
||||
/// </param>
|
||||
/// <returns>An absolute URI, or <c>null</c>.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The value of <paramref name="host" /> should be a trusted value. Relying on the value of the current request
|
||||
/// can allow untrusted input to influence the resulting URI unless the <c>Host</c> header has been validated.
|
||||
/// See the deployment documentation for instructions on how to properly validate the <c>Host</c> header in
|
||||
/// your deployment environment.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public abstract string GetUri(
|
||||
object values,
|
||||
string scheme,
|
||||
HostString host,
|
||||
PathString pathBase = default,
|
||||
FragmentString fragment = default,
|
||||
LinkOptions options = default);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -147,16 +147,5 @@ namespace Microsoft.AspNetCore.Routing
|
|||
PathString pathBase = default,
|
||||
FragmentString fragment = default,
|
||||
LinkOptions options = default);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="LinkGenerationTemplate"/> based on the provided <paramref name="address"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="TAddress">The address type.</typeparam>
|
||||
/// <param name="address">The address value. Used to resolve endpoints.</param>
|
||||
/// <param name="options">Options for the created <see cref="LinkGenerationTemplate"/>.</param>
|
||||
/// <returns>
|
||||
/// A <see cref="LinkGenerationTemplate"/> if one or more endpoints matching the address can be found, otherwise <c>null</c>.
|
||||
/// </returns>
|
||||
public abstract LinkGenerationTemplate GetTemplateByAddress<TAddress>(TAddress address, LinkGenerationTemplateOptions options = null);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,15 +14,20 @@ namespace Microsoft.AspNetCore.Routing
|
|||
/// </summary>
|
||||
public sealed class DefaultEndpointDataSource : EndpointDataSource
|
||||
{
|
||||
private readonly List<Endpoint> _endpoints;
|
||||
private readonly IReadOnlyList<Endpoint> _endpoints;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DefaultEndpointDataSource" /> class.
|
||||
/// </summary>
|
||||
/// <param name="endpoints">The <see cref="Endpoint"/> instances that the data source will return.</param>
|
||||
public DefaultEndpointDataSource(params Endpoint[] endpoints)
|
||||
: this((IEnumerable<Endpoint>) endpoints)
|
||||
{
|
||||
if (endpoints == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(endpoints));
|
||||
}
|
||||
|
||||
_endpoints = (Endpoint[])endpoints.Clone();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -36,8 +41,7 @@ namespace Microsoft.AspNetCore.Routing
|
|||
throw new ArgumentNullException(nameof(endpoints));
|
||||
}
|
||||
|
||||
_endpoints = new List<Endpoint>();
|
||||
_endpoints.AddRange(endpoints);
|
||||
_endpoints = new List<Endpoint>(endpoints);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -1,120 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing
|
||||
{
|
||||
internal sealed class DefaultLinkGenerationTemplate : LinkGenerationTemplate
|
||||
{
|
||||
public DefaultLinkGenerationTemplate(DefaultLinkGenerator linkGenerator, List<RouteEndpoint> endpoints, LinkGenerationTemplateOptions options)
|
||||
{
|
||||
LinkGenerator = linkGenerator;
|
||||
Endpoints = endpoints;
|
||||
Options = options;
|
||||
}
|
||||
|
||||
public DefaultLinkGenerator LinkGenerator { get; }
|
||||
|
||||
public List<RouteEndpoint> Endpoints { get; }
|
||||
|
||||
public LinkGenerationTemplateOptions Options { get; }
|
||||
|
||||
public override string GetPath(
|
||||
HttpContext httpContext,
|
||||
object values,
|
||||
PathString? pathBase = default,
|
||||
FragmentString fragment = default,
|
||||
LinkOptions options = default)
|
||||
{
|
||||
if (httpContext == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(httpContext));
|
||||
}
|
||||
|
||||
return LinkGenerator.GetPathByEndpoints(
|
||||
Endpoints,
|
||||
new RouteValueDictionary(values),
|
||||
GetAmbientValues(httpContext),
|
||||
pathBase ?? httpContext.Request.PathBase,
|
||||
fragment,
|
||||
options);
|
||||
}
|
||||
|
||||
public override string GetPath(
|
||||
object values,
|
||||
PathString pathBase = default,
|
||||
FragmentString fragment = default,
|
||||
LinkOptions options = default)
|
||||
{
|
||||
return LinkGenerator.GetPathByEndpoints(
|
||||
Endpoints,
|
||||
new RouteValueDictionary(values),
|
||||
ambientValues: null,
|
||||
pathBase: pathBase,
|
||||
fragment: fragment,
|
||||
options: options);
|
||||
}
|
||||
|
||||
public override string GetUri(
|
||||
HttpContext httpContext,
|
||||
object values,
|
||||
string scheme = default,
|
||||
HostString? host = default,
|
||||
PathString? pathBase = default,
|
||||
FragmentString fragment = default,
|
||||
LinkOptions options = default)
|
||||
{
|
||||
if (httpContext == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(httpContext));
|
||||
}
|
||||
|
||||
return LinkGenerator.GetUriByEndpoints(
|
||||
Endpoints,
|
||||
new RouteValueDictionary(values),
|
||||
GetAmbientValues(httpContext),
|
||||
scheme ?? httpContext.Request.Scheme,
|
||||
host ?? httpContext.Request.Host,
|
||||
pathBase ?? httpContext.Request.PathBase,
|
||||
fragment,
|
||||
options);
|
||||
}
|
||||
|
||||
public override string GetUri(
|
||||
object values,
|
||||
string scheme,
|
||||
HostString host,
|
||||
PathString pathBase = default,
|
||||
FragmentString fragment = default,
|
||||
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(
|
||||
Endpoints,
|
||||
new RouteValueDictionary(values),
|
||||
ambientValues: null,
|
||||
scheme: scheme,
|
||||
host: host,
|
||||
pathBase: pathBase,
|
||||
fragment: fragment,
|
||||
options: options);
|
||||
}
|
||||
|
||||
private RouteValueDictionary GetAmbientValues(HttpContext httpContext)
|
||||
{
|
||||
return (Options?.UseAmbientValues ?? false) ? DefaultLinkGenerator.GetAmbientValues(httpContext) : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -189,17 +189,6 @@ namespace Microsoft.AspNetCore.Routing
|
|||
options: options);
|
||||
}
|
||||
|
||||
public override LinkGenerationTemplate GetTemplateByAddress<TAddress>(TAddress address, LinkGenerationTemplateOptions options = default)
|
||||
{
|
||||
var endpoints = GetEndpoints(address);
|
||||
if (endpoints.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new DefaultLinkGenerationTemplate(this, endpoints, options);
|
||||
}
|
||||
|
||||
private List<RouteEndpoint> GetEndpoints<TAddress>(TAddress address)
|
||||
{
|
||||
var addressingScheme = _serviceProvider.GetRequiredService<IEndpointAddressScheme<TAddress>>();
|
||||
|
|
@ -217,7 +206,6 @@ namespace Microsoft.AspNetCore.Routing
|
|||
return endpoints;
|
||||
}
|
||||
|
||||
// Also called from DefaultLinkGenerationTemplate
|
||||
public string GetPathByEndpoints(
|
||||
List<RouteEndpoint> endpoints,
|
||||
RouteValueDictionary values,
|
||||
|
|
|
|||
|
|
@ -242,18 +242,29 @@ namespace Microsoft.AspNetCore.Routing.Internal
|
|||
// Used by TemplateBinder.TryBindValues - the new code path of LinkGenerator
|
||||
public PathString ToPathString()
|
||||
{
|
||||
if (_path.Length > 0 && _path[0] != '/')
|
||||
PathString pathString;
|
||||
|
||||
if (_path.Length > 0)
|
||||
{
|
||||
// Normalize generated paths so that they always contain a leading slash.
|
||||
_path.Insert(0, '/');
|
||||
if (_path[0] != '/')
|
||||
{
|
||||
// Normalize generated paths so that they always contain a leading slash.
|
||||
_path.Insert(0, '/');
|
||||
}
|
||||
|
||||
if (AppendTrailingSlash && _path[_path.Length - 1] != '/')
|
||||
{
|
||||
_path.Append('/');
|
||||
}
|
||||
|
||||
pathString = new PathString(_path.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
pathString = PathString.Empty;
|
||||
}
|
||||
|
||||
if (AppendTrailingSlash && _path.Length > 0 && _path[_path.Length - 1] != '/')
|
||||
{
|
||||
_path.Append('/');
|
||||
}
|
||||
|
||||
return new PathString(_path.ToString());
|
||||
return pathString;
|
||||
}
|
||||
|
||||
// Used by TemplateBinder.TryBindValues - the new code path of LinkGenerator
|
||||
|
|
|
|||
|
|
@ -11,11 +11,6 @@ namespace Microsoft.AspNetCore.Routing
|
|||
/// </summary>
|
||||
public static class LinkGeneratorEndpointNameAddressExtensions
|
||||
{
|
||||
private static readonly LinkGenerationTemplateOptions _templateOptions = new LinkGenerationTemplateOptions()
|
||||
{
|
||||
UseAmbientValues = false,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Generates a URI with an absolute path based on the provided values.
|
||||
/// </summary>
|
||||
|
|
@ -227,28 +222,5 @@ namespace Microsoft.AspNetCore.Routing
|
|||
|
||||
return generator.GetUriByAddress<string>(endpointName, new RouteValueDictionary(values), scheme, host, pathBase, fragment, options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="LinkGenerationTemplate"/> based on the provided <paramref name="endpointName"/>.
|
||||
/// </summary>
|
||||
/// <param name="generator">The <see cref="LinkGenerator"/>.</param>
|
||||
/// <param name="endpointName">The endpoint name. Used to resolve endpoints. Optional.</param>
|
||||
/// <returns>
|
||||
/// A <see cref="LinkGenerationTemplate"/> if one or more endpoints matching the address can be found, otherwise <c>null</c>.
|
||||
/// </returns>
|
||||
public static LinkGenerationTemplate GetTemplateByName(this LinkGenerator generator, string endpointName)
|
||||
{
|
||||
if (generator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(generator));
|
||||
}
|
||||
|
||||
if (endpointName == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(endpointName));
|
||||
}
|
||||
|
||||
return generator.GetTemplateByAddress<string>(endpointName, _templateOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,11 +11,6 @@ namespace Microsoft.AspNetCore.Routing
|
|||
/// </summary>
|
||||
public static class LinkGeneratorRouteValuesAddressExtensions
|
||||
{
|
||||
private static readonly LinkGenerationTemplateOptions _templateOptions = new LinkGenerationTemplateOptions()
|
||||
{
|
||||
UseAmbientValues = true,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Generates a URI with an absolute path based on the provided values.
|
||||
/// </summary>
|
||||
|
|
@ -202,29 +197,6 @@ namespace Microsoft.AspNetCore.Routing
|
|||
return generator.GetUriByAddress<RouteValuesAddress>(address, address.ExplicitValues, scheme, host, pathBase, fragment, options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="LinkGenerationTemplate"/> based on the provided <paramref name="routeName"/> and <paramref name="values"/>.
|
||||
/// </summary>
|
||||
/// <param name="generator">The <see cref="LinkGenerator"/>.</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>
|
||||
/// <returns>
|
||||
/// A <see cref="LinkGenerationTemplate"/> if one or more endpoints matching the address can be found, otherwise <c>null</c>.
|
||||
/// </returns>
|
||||
public static LinkGenerationTemplate GetTemplateByRouteValues(
|
||||
this LinkGenerator generator,
|
||||
string routeName,
|
||||
object values)
|
||||
{
|
||||
if (generator == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(generator));
|
||||
}
|
||||
|
||||
var address = CreateAddress(httpContext: null, routeName, values);
|
||||
return generator.GetTemplateByAddress<RouteValuesAddress>(address, _templateOptions);
|
||||
}
|
||||
|
||||
private static RouteValuesAddress CreateAddress(HttpContext httpContext, string routeName, object values)
|
||||
{
|
||||
return new RouteValuesAddress()
|
||||
|
|
|
|||
|
|
@ -75,16 +75,20 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
int? foundScore = null;
|
||||
for (var i = 0; i < candidateSet.Count; i++)
|
||||
{
|
||||
if (!candidateSet.IsValidCandidate(i))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ref var state = ref candidateSet[i];
|
||||
var isValid = candidateSet.IsValidCandidate(i);
|
||||
if (isValid && foundScore == null)
|
||||
if (foundScore == null)
|
||||
{
|
||||
// This is the first match we've seen - speculatively assign it.
|
||||
endpoint = state.Endpoint;
|
||||
values = state.Values;
|
||||
foundScore = state.Score;
|
||||
}
|
||||
else if (isValid && foundScore < state.Score)
|
||||
else if (foundScore < state.Score)
|
||||
{
|
||||
// This candidate is lower priority than the one we've seen
|
||||
// so far, we can stop.
|
||||
|
|
@ -92,7 +96,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
|||
// Don't worry about the 'null < state.Score' case, it returns false.
|
||||
break;
|
||||
}
|
||||
else if (isValid && foundScore == state.Score)
|
||||
else if (foundScore == state.Score)
|
||||
{
|
||||
// This is the second match we've found of the same score, so there
|
||||
// must be an ambiguity.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -26,6 +25,34 @@ namespace Microsoft.AspNetCore.Routing
|
|||
endpoint => Assert.Equal("2", endpoint.DisplayName));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_Params_ShouldMakeCopyOfEndpoints()
|
||||
{
|
||||
// Arrange
|
||||
var endpoint1 = new Endpoint(TestConstants.EmptyRequestDelegate, EndpointMetadataCollection.Empty, "1");
|
||||
var endpoint2 = new Endpoint(TestConstants.EmptyRequestDelegate, EndpointMetadataCollection.Empty, "2");
|
||||
var endpoints = new[] { endpoint1, endpoint2 };
|
||||
|
||||
// Act
|
||||
var dataSource = new DefaultEndpointDataSource(endpoints);
|
||||
Array.Resize(ref endpoints, 1);
|
||||
endpoints[0] = null;
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, dataSource.Endpoints.Count);
|
||||
Assert.Contains(endpoint1, dataSource.Endpoints);
|
||||
Assert.Contains(endpoint2, dataSource.Endpoints);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_Params_ShouldThrowArgumentNullExceptionWhenEndpointsIsNull()
|
||||
{
|
||||
Endpoint[] endpoints = null;
|
||||
|
||||
var actual = Assert.Throws<ArgumentNullException>(() => new DefaultEndpointDataSource(endpoints));
|
||||
Assert.Equal("endpoints", actual.ParamName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_Enumerable_EndpointsInitialized()
|
||||
{
|
||||
|
|
@ -41,5 +68,33 @@ namespace Microsoft.AspNetCore.Routing
|
|||
endpoint => Assert.Equal("1", endpoint.DisplayName),
|
||||
endpoint => Assert.Equal("2", endpoint.DisplayName));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_Enumerable_ShouldMakeCopyOfEndpoints()
|
||||
{
|
||||
// Arrange
|
||||
var endpoint1 = new Endpoint(TestConstants.EmptyRequestDelegate, EndpointMetadataCollection.Empty, "1");
|
||||
var endpoint2 = new Endpoint(TestConstants.EmptyRequestDelegate, EndpointMetadataCollection.Empty, "2");
|
||||
var endpoints = new List<Endpoint> { endpoint1, endpoint2 };
|
||||
|
||||
// Act
|
||||
var dataSource = new DefaultEndpointDataSource((IEnumerable<Endpoint>)endpoints);
|
||||
endpoints.RemoveAt(0);
|
||||
endpoints[0] = null;
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, dataSource.Endpoints.Count);
|
||||
Assert.Contains(endpoint1, dataSource.Endpoints);
|
||||
Assert.Contains(endpoint2, dataSource.Endpoints);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_Enumerable_ShouldThrowArgumentNullExceptionWhenEndpointsIsNull()
|
||||
{
|
||||
IEnumerable<Endpoint> endpoints = null;
|
||||
|
||||
var actual = Assert.Throws<ArgumentNullException>(() => new DefaultEndpointDataSource(endpoints));
|
||||
Assert.Equal("endpoints", actual.ParamName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,207 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing
|
||||
{
|
||||
// Tests DefaultLinkGenerationTemplate functionality - these are pretty light since most of the functionality
|
||||
// is a direct subset of DefaultLinkGenerator
|
||||
//
|
||||
// Does not cover template processing in detail, those scenarios are validated by TemplateBinderTests
|
||||
// and DefaultLinkGeneratorProcessTemplateTest
|
||||
public class DefaultLinkGenerationTemplateTest : LinkGeneratorTestBase
|
||||
{
|
||||
[Fact]
|
||||
public void GetPath_WithoutHttpContext_WithPathBaseAndFragment()
|
||||
{
|
||||
// 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: null);
|
||||
|
||||
// Act
|
||||
var path = template.GetPath(
|
||||
values: new RouteValueDictionary(new { controller = "Home", action = "In?dex", query = "some?query" }),
|
||||
new PathString("/Foo/Bar?encodeme?"),
|
||||
new FragmentString("#Fragment?"),
|
||||
new LinkOptions() { AppendTrailingSlash = true, });
|
||||
|
||||
// Assert
|
||||
Assert.Equal("/Foo/Bar%3Fencodeme%3F/Home/In%3Fdex/?query=some%3Fquery#Fragment?", path);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetPath_WithHttpContext_WithPathBaseAndFragment()
|
||||
{
|
||||
// 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: null);
|
||||
|
||||
var httpContext = CreateHttpContext();
|
||||
httpContext.Request.PathBase = new PathString("/Foo/Bar?encodeme?");
|
||||
|
||||
// Act
|
||||
var path = template.GetPath(
|
||||
httpContext,
|
||||
values: new RouteValueDictionary(new { controller = "Home", action = "In?dex", query = "some?query" }),
|
||||
fragment: new FragmentString("#Fragment?"),
|
||||
options: new LinkOptions() { AppendTrailingSlash = true, });
|
||||
|
||||
// Assert
|
||||
Assert.Equal("/Foo/Bar%3Fencodeme%3F/Home/In%3Fdex/?query=some%3Fquery#Fragment?", path);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetUri_WithoutHttpContext_WithPathBaseAndFragment()
|
||||
{
|
||||
// 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: null);
|
||||
|
||||
// Act
|
||||
var path = template.GetUri(
|
||||
values: new RouteValueDictionary(new { controller = "Home", action = "In?dex", query = "some?query" }),
|
||||
"http",
|
||||
new HostString("example.com"),
|
||||
new PathString("/Foo/Bar?encodeme?"),
|
||||
new FragmentString("#Fragment?"),
|
||||
new LinkOptions() { AppendTrailingSlash = true, });
|
||||
|
||||
// Assert
|
||||
Assert.Equal("http://example.com/Foo/Bar%3Fencodeme%3F/Home/In%3Fdex/?query=some%3Fquery#Fragment?", path);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetUri_WithHttpContext_WithPathBaseAndFragment()
|
||||
{
|
||||
// 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: null);
|
||||
|
||||
var httpContext = CreateHttpContext();
|
||||
httpContext.Request.Scheme = "http";
|
||||
httpContext.Request.Host = new HostString("example.com");
|
||||
httpContext.Request.PathBase = new PathString("/Foo/Bar?encodeme?");
|
||||
|
||||
// Act
|
||||
var uri = template.GetUri(
|
||||
httpContext,
|
||||
values: new RouteValueDictionary(new { controller = "Home", action = "In?dex", query = "some?query" }),
|
||||
fragment: new FragmentString("#Fragment?"),
|
||||
options: new LinkOptions() { AppendTrailingSlash = true, });
|
||||
|
||||
// Assert
|
||||
Assert.Equal("http://example.com/Foo/Bar%3Fencodeme%3F/Home/In%3Fdex/?query=some%3Fquery#Fragment?", uri);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetPath_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", });
|
||||
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.Equal("/Home/Index", uri);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetPath_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.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", });
|
||||
httpContext.Request.Scheme = "http";
|
||||
httpContext.Request.Host = new HostString("example.com");
|
||||
|
||||
// Act
|
||||
var uri = template.GetUri(httpContext, values: new { action = "Index", });
|
||||
|
||||
// Assert
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -524,42 +524,6 @@ namespace Microsoft.AspNetCore.Routing
|
|||
Assert.Equal("ftp://example.com:5000/Home/Index", uri);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTemplateByAddress_WithNoMatch_ReturnsNull()
|
||||
{
|
||||
// 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);
|
||||
|
||||
// Act
|
||||
var template = linkGenerator.GetTemplateByAddress(address: 0);
|
||||
|
||||
// Assert
|
||||
Assert.Null(template);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTemplateByAddress_WithMatch_ReturnsTemplate()
|
||||
{
|
||||
// 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);
|
||||
|
||||
// Act
|
||||
var template = linkGenerator.GetTemplateByAddress(address: 1);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(template);
|
||||
Assert.Collection(
|
||||
Assert.IsType<DefaultLinkGenerationTemplate>(template).Endpoints,
|
||||
e => Assert.Same(endpoint1, e),
|
||||
e => Assert.Same(endpoint2, e));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTemplateBinder_CanCache()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -65,5 +65,36 @@ namespace Microsoft.AspNetCore.Routing.Internal
|
|||
// Assert
|
||||
Assert.Equal(expected, uriBuilldingContext.ToString());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("/Author", false, false, "/UrlEncode[[Author]]")]
|
||||
[InlineData("/Author", false, true, "/UrlEncode[[Author]]")]
|
||||
[InlineData("/Author", true, false, "/UrlEncode[[Author]]/")]
|
||||
[InlineData("/Author", true, true, "/UrlEncode[[Author]]/")]
|
||||
[InlineData("/Author/", false, false, "/UrlEncode[[Author]]/")]
|
||||
[InlineData("/Author/", false, true, "/UrlEncode[[Author/]]")]
|
||||
[InlineData("/Author/", true, false, "/UrlEncode[[Author]]/")]
|
||||
[InlineData("/Author/", true, true, "/UrlEncode[[Author/]]/")]
|
||||
[InlineData("Author", false, false, "/UrlEncode[[Author]]")]
|
||||
[InlineData("Author", false, true, "/UrlEncode[[Author]]")]
|
||||
[InlineData("Author", true, false, "/UrlEncode[[Author]]/")]
|
||||
[InlineData("Author", true, true, "/UrlEncode[[Author]]/")]
|
||||
[InlineData("", false, false, "")]
|
||||
[InlineData("", false, true, "")]
|
||||
[InlineData("", true, false, "")]
|
||||
[InlineData("", true, true, "")]
|
||||
public void ToPathString(string url, bool appendTrailingSlash, bool encodeSlashes, string expected)
|
||||
{
|
||||
// Arrange
|
||||
var urlTestEncoder = new UrlTestEncoder();
|
||||
var uriBuilldingContext = new UriBuildingContext(urlTestEncoder);
|
||||
uriBuilldingContext.AppendTrailingSlash = appendTrailingSlash;
|
||||
|
||||
// Act
|
||||
uriBuilldingContext.Accept(url, encodeSlashes);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, uriBuilldingContext.ToPathString().Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -149,24 +149,5 @@ namespace Microsoft.AspNetCore.Routing
|
|||
// Assert
|
||||
Assert.Equal("http://example.com/Foo/Bar%3Fencodeme%3F/some%23-other-endpoint/In%3Fdex/?query=some%3Fquery#Fragment?", uri);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTemplateByName_CreatesTemplate()
|
||||
{
|
||||
// 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);
|
||||
|
||||
// Act
|
||||
var template = linkGenerator.GetTemplateByName(endpointName: "name2");
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(template);
|
||||
Assert.Collection(
|
||||
Assert.IsType<DefaultLinkGenerationTemplate>(template).Endpoints.Cast<RouteEndpoint>().OrderBy(e => e.RoutePattern.RawText),
|
||||
e => Assert.Same(endpoint2, e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -201,31 +201,5 @@ namespace Microsoft.AspNetCore.Routing
|
|||
// Assert
|
||||
Assert.Equal("http://example.com/Foo/Bar%3Fencodeme%3F/Home/Index/?query=some%3Fquery#Fragment?", uri);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTemplateByRouteValues_CreatesTemplate()
|
||||
{
|
||||
// Arrange
|
||||
var endpoint1 = EndpointFactory.CreateRouteEndpoint(
|
||||
"{controller}/{action}/{id}",
|
||||
metadata: new[] { new RouteValuesAddressMetadata(new RouteValueDictionary(new { controller = "Home", action = "In?dex", })) });
|
||||
var endpoint2 = EndpointFactory.CreateRouteEndpoint(
|
||||
"{controller}/{action}/{id?}",
|
||||
metadata: new[] { new RouteValuesAddressMetadata(new RouteValueDictionary(new { controller = "Home", action = "In?dex", })) });
|
||||
|
||||
var linkGenerator = CreateLinkGenerator(endpoint1, endpoint2);
|
||||
|
||||
// Act
|
||||
var template = linkGenerator.GetTemplateByRouteValues(
|
||||
routeName: null,
|
||||
values: new RouteValueDictionary(new { controller = "Home", action = "In?dex", query = "some?query" }));
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(template);
|
||||
Assert.Collection(
|
||||
Assert.IsType<DefaultLinkGenerationTemplate>(template).Endpoints.Cast<RouteEndpoint>().OrderBy(e => e.RoutePattern.RawText),
|
||||
e => Assert.Same(endpoint2, e),
|
||||
e => Assert.Same(endpoint1, e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue