Merge branch 'merge/release/2.2-to-master'
This commit is contained in:
commit
167b80f543
|
|
@ -1,24 +1,13 @@
|
||||||
// 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 System.Collections.Generic;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
public abstract class LinkGenerator
|
public abstract class LinkGenerator
|
||||||
{
|
{
|
||||||
public abstract bool TryGetLink(
|
public abstract bool TryGetLink(LinkGeneratorContext context, out string link);
|
||||||
HttpContext httpContext,
|
|
||||||
IEnumerable<Endpoint> endpoints,
|
|
||||||
RouteValueDictionary explicitValues,
|
|
||||||
RouteValueDictionary ambientValues,
|
|
||||||
out string link);
|
|
||||||
|
|
||||||
public abstract string GetLink(
|
public abstract string GetLink(LinkGeneratorContext context);
|
||||||
HttpContext httpContext,
|
|
||||||
IEnumerable<Endpoint> endpoints,
|
|
||||||
RouteValueDictionary explicitValues,
|
|
||||||
RouteValueDictionary ambientValues);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Routing
|
||||||
|
{
|
||||||
|
public class LinkGeneratorContext
|
||||||
|
{
|
||||||
|
public HttpContext HttpContext { get; set; }
|
||||||
|
|
||||||
|
public IEnumerable<Endpoint> Endpoints { get; set; }
|
||||||
|
|
||||||
|
public RouteValueDictionary ExplicitValues { get; set; }
|
||||||
|
|
||||||
|
public RouteValueDictionary AmbientValues { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether all generated paths URLs are lower-case.
|
||||||
|
/// Use <see cref="LowercaseQueryStrings" /> to configure the behavior for query strings.
|
||||||
|
/// </summary>
|
||||||
|
public bool? LowercaseUrls { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether a generated query strings are lower-case.
|
||||||
|
/// This property will be unless <see cref="LowercaseUrls" /> is also <c>true</c>.
|
||||||
|
/// </summary>
|
||||||
|
public bool? LowercaseQueryStrings { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether a trailing slash should be appended to the generated URLs.
|
||||||
|
/// </summary>
|
||||||
|
public bool? AppendTrailingSlash { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
@ -11,32 +10,38 @@ using Microsoft.AspNetCore.Routing.Matchers;
|
||||||
using Microsoft.AspNetCore.Routing.Template;
|
using Microsoft.AspNetCore.Routing.Template;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.ObjectPool;
|
using Microsoft.Extensions.ObjectPool;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
internal class DefaultLinkGenerator : LinkGenerator
|
internal class DefaultLinkGenerator : LinkGenerator
|
||||||
{
|
{
|
||||||
|
private readonly static char[] UrlQueryDelimiters = new char[] { '?', '#' };
|
||||||
private readonly MatchProcessorFactory _matchProcessorFactory;
|
private readonly MatchProcessorFactory _matchProcessorFactory;
|
||||||
private readonly ObjectPool<UriBuildingContext> _uriBuildingContextPool;
|
private readonly ObjectPool<UriBuildingContext> _uriBuildingContextPool;
|
||||||
|
private readonly RouteOptions _options;
|
||||||
private readonly ILogger<DefaultLinkGenerator> _logger;
|
private readonly ILogger<DefaultLinkGenerator> _logger;
|
||||||
|
|
||||||
public DefaultLinkGenerator(
|
public DefaultLinkGenerator(
|
||||||
MatchProcessorFactory matchProcessorFactory,
|
MatchProcessorFactory matchProcessorFactory,
|
||||||
ObjectPool<UriBuildingContext> uriBuildingContextPool,
|
ObjectPool<UriBuildingContext> uriBuildingContextPool,
|
||||||
|
IOptions<RouteOptions> routeOptions,
|
||||||
ILogger<DefaultLinkGenerator> logger)
|
ILogger<DefaultLinkGenerator> logger)
|
||||||
{
|
{
|
||||||
_matchProcessorFactory = matchProcessorFactory;
|
_matchProcessorFactory = matchProcessorFactory;
|
||||||
_uriBuildingContextPool = uriBuildingContextPool;
|
_uriBuildingContextPool = uriBuildingContextPool;
|
||||||
|
_options = routeOptions.Value;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string GetLink(
|
public override string GetLink(LinkGeneratorContext context)
|
||||||
HttpContext httpContext,
|
|
||||||
IEnumerable<Endpoint> endpoints,
|
|
||||||
RouteValueDictionary explicitValues,
|
|
||||||
RouteValueDictionary ambientValues)
|
|
||||||
{
|
{
|
||||||
if (TryGetLink(httpContext, endpoints, explicitValues, ambientValues, out var link))
|
if (context == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TryGetLink(context, out var link))
|
||||||
{
|
{
|
||||||
return link;
|
return link;
|
||||||
}
|
}
|
||||||
|
|
@ -44,21 +49,21 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
throw new InvalidOperationException("Could not find a matching endpoint to generate a link.");
|
throw new InvalidOperationException("Could not find a matching endpoint to generate a link.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool TryGetLink(
|
public override bool TryGetLink(LinkGeneratorContext context, out string link)
|
||||||
HttpContext httpContext,
|
|
||||||
IEnumerable<Endpoint> endpoints,
|
|
||||||
RouteValueDictionary explicitValues,
|
|
||||||
RouteValueDictionary ambientValues,
|
|
||||||
out string link)
|
|
||||||
{
|
{
|
||||||
|
if (context == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(context));
|
||||||
|
}
|
||||||
|
|
||||||
link = null;
|
link = null;
|
||||||
|
|
||||||
if (endpoints == null)
|
if (context.Endpoints == null)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var matcherEndpoints = endpoints.OfType<MatcherEndpoint>();
|
var matcherEndpoints = context.Endpoints.OfType<MatcherEndpoint>();
|
||||||
if (!matcherEndpoints.Any())
|
if (!matcherEndpoints.Any())
|
||||||
{
|
{
|
||||||
//todo:log here
|
//todo:log here
|
||||||
|
|
@ -67,7 +72,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
foreach (var endpoint in matcherEndpoints)
|
foreach (var endpoint in matcherEndpoints)
|
||||||
{
|
{
|
||||||
link = GetLink(httpContext, endpoint, explicitValues, ambientValues);
|
link = GetLink(endpoint, context);
|
||||||
if (link != null)
|
if (link != null)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -77,11 +82,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetLink(
|
private string GetLink(MatcherEndpoint endpoint, LinkGeneratorContext context)
|
||||||
HttpContext httpContext,
|
|
||||||
MatcherEndpoint endpoint,
|
|
||||||
RouteValueDictionary explicitValues,
|
|
||||||
RouteValueDictionary ambientValues)
|
|
||||||
{
|
{
|
||||||
var templateBinder = new TemplateBinder(
|
var templateBinder = new TemplateBinder(
|
||||||
UrlEncoder.Default,
|
UrlEncoder.Default,
|
||||||
|
|
@ -89,28 +90,34 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
new RouteTemplate(endpoint.RoutePattern),
|
new RouteTemplate(endpoint.RoutePattern),
|
||||||
new RouteValueDictionary(endpoint.RoutePattern.Defaults));
|
new RouteValueDictionary(endpoint.RoutePattern.Defaults));
|
||||||
|
|
||||||
var templateValuesResult = templateBinder.GetValues(ambientValues, explicitValues);
|
var templateValuesResult = templateBinder.GetValues(
|
||||||
|
ambientValues: context.AmbientValues,
|
||||||
|
values: context.ExplicitValues);
|
||||||
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.
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Match(httpContext, endpoint, templateValuesResult.CombinedValues))
|
if (!MatchesConstraints(context.HttpContext, endpoint, templateValuesResult.CombinedValues))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return templateBinder.BindValues(templateValuesResult.AcceptedValues);
|
var url = templateBinder.BindValues(templateValuesResult.AcceptedValues);
|
||||||
|
return Normalize(context, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool Match(HttpContext httpContext, MatcherEndpoint endpoint, RouteValueDictionary routeValues)
|
private bool MatchesConstraints(
|
||||||
|
HttpContext httpContext,
|
||||||
|
MatcherEndpoint endpoint,
|
||||||
|
RouteValueDictionary routeValues)
|
||||||
{
|
{
|
||||||
if (routeValues == null)
|
if (routeValues == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(routeValues));
|
throw new ArgumentNullException(nameof(routeValues));
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var kvp in endpoint.RoutePattern.Constraints)
|
foreach (var kvp in endpoint.RoutePattern.Constraints)
|
||||||
{
|
{
|
||||||
var parameter = endpoint.RoutePattern.GetParameter(kvp.Key); // may be null, that's ok
|
var parameter = endpoint.RoutePattern.GetParameter(kvp.Key); // may be null, that's ok
|
||||||
|
|
@ -128,5 +135,47 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string Normalize(LinkGeneratorContext context, string url)
|
||||||
|
{
|
||||||
|
var lowercaseUrls = context.LowercaseUrls.HasValue ? context.LowercaseUrls.Value : _options.LowercaseUrls;
|
||||||
|
var lowercaseQueryStrings = context.LowercaseQueryStrings.HasValue ?
|
||||||
|
context.LowercaseQueryStrings.Value : _options.LowercaseQueryStrings;
|
||||||
|
var appendTrailingSlash = context.AppendTrailingSlash.HasValue ?
|
||||||
|
context.AppendTrailingSlash.Value : _options.AppendTrailingSlash;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(url) && (lowercaseUrls || appendTrailingSlash))
|
||||||
|
{
|
||||||
|
var indexOfSeparator = url.IndexOfAny(UrlQueryDelimiters);
|
||||||
|
var urlWithoutQueryString = url;
|
||||||
|
var queryString = string.Empty;
|
||||||
|
|
||||||
|
if (indexOfSeparator != -1)
|
||||||
|
{
|
||||||
|
urlWithoutQueryString = url.Substring(0, indexOfSeparator);
|
||||||
|
queryString = url.Substring(indexOfSeparator);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lowercaseUrls)
|
||||||
|
{
|
||||||
|
urlWithoutQueryString = urlWithoutQueryString.ToLowerInvariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lowercaseUrls && lowercaseQueryStrings)
|
||||||
|
{
|
||||||
|
queryString = queryString.ToLowerInvariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (appendTrailingSlash && !urlWithoutQueryString.EndsWith("/", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
urlWithoutQueryString += "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
// queryString will contain the delimiter ? or # as the first character, so it's safe to append.
|
||||||
|
url = urlWithoutQueryString + queryString;
|
||||||
|
}
|
||||||
|
|
||||||
|
return url;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether a generated query strings are lower-case.
|
/// Gets or sets a value indicating whether a generated query strings are lower-case.
|
||||||
/// This property will be unless <see cref="LowercaseUrls" /> is also <c>true</c>
|
/// This property will not be used unless <see cref="LowercaseUrls" /> is also <c>true</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool LowercaseQueryStrings { get; set; }
|
public bool LowercaseQueryStrings { get; set; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
private readonly CompositeEndpointDataSource _endpointDataSource;
|
private readonly CompositeEndpointDataSource _endpointDataSource;
|
||||||
private readonly ObjectPool<UriBuildingContext> _objectPool;
|
private readonly ObjectPool<UriBuildingContext> _objectPool;
|
||||||
private LinkGenerationDecisionTree _allMatchesLinkGenerationTree;
|
private LinkGenerationDecisionTree _allMatchesLinkGenerationTree;
|
||||||
private IDictionary<string, LinkGenerationDecisionTree> _namedMatches;
|
private IDictionary<string, List<OutboundMatchResult>> _namedMatchResults;
|
||||||
|
|
||||||
public RouteValuesBasedEndpointFinder(
|
public RouteValuesBasedEndpointFinder(
|
||||||
CompositeEndpointDataSource endpointDataSource,
|
CompositeEndpointDataSource endpointDataSource,
|
||||||
|
|
@ -45,11 +45,9 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
context.ExplicitValues,
|
context.ExplicitValues,
|
||||||
context.AmbientValues);
|
context.AmbientValues);
|
||||||
}
|
}
|
||||||
else if (_namedMatches.TryGetValue(context.RouteName, out var linkGenerationTree))
|
else if (_namedMatchResults.TryGetValue(context.RouteName, out var namedMatchResults))
|
||||||
{
|
{
|
||||||
matchResults = linkGenerationTree.GetMatches(
|
matchResults = namedMatchResults;
|
||||||
context.ExplicitValues,
|
|
||||||
context.AmbientValues);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matchResults == null || !matchResults.Any())
|
if (matchResults == null || !matchResults.Any())
|
||||||
|
|
@ -78,15 +76,33 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
// Refresh the matches in the case where a datasource's endpoints changes. The following is OK to do
|
// Refresh the matches in the case where a datasource's endpoints changes. The following is OK to do
|
||||||
// as refresh of new endpoints happens within a lock and also these fields are not publicly accessible.
|
// as refresh of new endpoints happens within a lock and also these fields are not publicly accessible.
|
||||||
var (allMatches, namedMatches) = GetOutboundMatches();
|
var (allMatches, namedMatchResults) = GetOutboundMatches();
|
||||||
_namedMatches = GetNamedMatches(namedMatches);
|
_namedMatchResults = namedMatchResults;
|
||||||
_allMatchesLinkGenerationTree = new LinkGenerationDecisionTree(allMatches.ToArray());
|
_allMatchesLinkGenerationTree = new LinkGenerationDecisionTree(allMatches.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual (IEnumerable<OutboundMatch>, IDictionary<string, List<OutboundMatch>>) GetOutboundMatches()
|
/// Decision tree is built using the 'required values' of actions.
|
||||||
|
/// - When generating a url using route values, decision tree checks the explicitly supplied route values +
|
||||||
|
/// ambient values to see if they have a match for the required-values-based-tree.
|
||||||
|
/// - When generating a url using route name, route values for controller, action etc.might not be provided
|
||||||
|
/// (this is expected because as a user I want to avoid writing all those and instead chose to use a
|
||||||
|
/// routename which is quick). So since these values are not provided and might not be even in ambient
|
||||||
|
/// values, decision tree would fail to find a match. So for this reason decision tree is not used for named
|
||||||
|
/// matches. Instead all named matches are returned as is and the LinkGenerator uses a TemplateBinder to
|
||||||
|
/// decide which of the matches can generate a url.
|
||||||
|
/// For example, for a route defined like below with current ambient values like new { controller = "Home",
|
||||||
|
/// action = "Index" }
|
||||||
|
/// "api/orders/{id}",
|
||||||
|
/// routeName: "OrdersApi",
|
||||||
|
/// defaults: new { controller = "Orders", action = "GetById" },
|
||||||
|
/// requiredValues: new { controller = "Orders", action = "GetById" },
|
||||||
|
/// A call to GetLink("OrdersApi", new { id = "10" }) cannot generate url as neither the supplied values or
|
||||||
|
/// current ambient values do not satisfy the decision tree that is built based on the required values.
|
||||||
|
protected virtual (IEnumerable<OutboundMatch>, IDictionary<string, List<OutboundMatchResult>>) GetOutboundMatches()
|
||||||
{
|
{
|
||||||
var allOutboundMatches = new List<OutboundMatch>();
|
var allOutboundMatches = new List<OutboundMatch>();
|
||||||
var namedOutboundMatches = new Dictionary<string, List<OutboundMatch>>(StringComparer.OrdinalIgnoreCase);
|
var namedOutboundMatchResults = new Dictionary<string, List<OutboundMatchResult>>(
|
||||||
|
StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
var endpoints = _endpointDataSource.Endpoints.OfType<MatcherEndpoint>();
|
var endpoints = _endpointDataSource.Endpoints.OfType<MatcherEndpoint>();
|
||||||
foreach (var endpoint in endpoints)
|
foreach (var endpoint in endpoints)
|
||||||
|
|
@ -101,16 +117,16 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<OutboundMatch> matches;
|
List<OutboundMatchResult> matchResults;
|
||||||
if (!namedOutboundMatches.TryGetValue(entry.RouteName, out matches))
|
if (!namedOutboundMatchResults.TryGetValue(entry.RouteName, out matchResults))
|
||||||
{
|
{
|
||||||
matches = new List<OutboundMatch>();
|
matchResults = new List<OutboundMatchResult>();
|
||||||
namedOutboundMatches.Add(entry.RouteName, matches);
|
namedOutboundMatchResults.Add(entry.RouteName, matchResults);
|
||||||
}
|
}
|
||||||
matches.Add(outboundMatch);
|
matchResults.Add(new OutboundMatchResult(outboundMatch, isFallbackMatch: false));
|
||||||
}
|
}
|
||||||
|
|
||||||
return (allOutboundMatches, namedOutboundMatches);
|
return (allOutboundMatches, namedOutboundMatchResults);
|
||||||
}
|
}
|
||||||
|
|
||||||
private OutboundRouteEntry CreateOutboundRouteEntry(MatcherEndpoint endpoint)
|
private OutboundRouteEntry CreateOutboundRouteEntry(MatcherEndpoint endpoint)
|
||||||
|
|
@ -129,16 +145,5 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
entry.Defaults = new RouteValueDictionary(endpoint.RoutePattern.Defaults);
|
entry.Defaults = new RouteValueDictionary(endpoint.RoutePattern.Defaults);
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IDictionary<string, LinkGenerationDecisionTree> GetNamedMatches(
|
|
||||||
IDictionary<string, List<OutboundMatch>> namedOutboundMatches)
|
|
||||||
{
|
|
||||||
var result = new Dictionary<string, LinkGenerationDecisionTree>(StringComparer.OrdinalIgnoreCase);
|
|
||||||
foreach (var namedOutboundMatch in namedOutboundMatches)
|
|
||||||
{
|
|
||||||
result.Add(namedOutboundMatch.Key, new LinkGenerationDecisionTree(namedOutboundMatch.Value.ToArray()));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Routing.Constraints;
|
using Microsoft.AspNetCore.Routing.Constraints;
|
||||||
using Microsoft.AspNetCore.Routing.EndpointFinders;
|
using Microsoft.AspNetCore.Routing.EndpointFinders;
|
||||||
|
|
@ -32,10 +31,12 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var link = linkGenerator.GetLink(
|
var link = linkGenerator.GetLink(
|
||||||
httpContext: null,
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
Endpoints = new[] { endpoint },
|
||||||
context.AmbientValues);
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("/Home", link);
|
Assert.Equal("/Home", link);
|
||||||
|
|
@ -53,10 +54,12 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
var exception = Assert.Throws<InvalidOperationException>(
|
var exception = Assert.Throws<InvalidOperationException>(
|
||||||
() => linkGenerator.GetLink(
|
() => linkGenerator.GetLink(
|
||||||
httpContext: null,
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
Endpoints = new[] { endpoint },
|
||||||
context.AmbientValues));
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
}));
|
||||||
Assert.Equal(expectedMessage, exception.Message);
|
Assert.Equal(expectedMessage, exception.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -70,10 +73,12 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var canGenerateLink = linkGenerator.TryGetLink(
|
var canGenerateLink = linkGenerator.TryGetLink(
|
||||||
httpContext: null,
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
Endpoints = new[] { endpoint },
|
||||||
context.AmbientValues,
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
},
|
||||||
out var link);
|
out var link);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
@ -93,10 +98,12 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var link = linkGenerator.GetLink(
|
var link = linkGenerator.GetLink(
|
||||||
httpContext: null,
|
new LinkGeneratorContext
|
||||||
new[] { endpoint1, endpoint2, endpoint3 },
|
{
|
||||||
context.ExplicitValues,
|
Endpoints = new[] { endpoint1, endpoint2, endpoint3 },
|
||||||
context.AmbientValues);
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("/Home/Index/10", link);
|
Assert.Equal("/Home/Index/10", link);
|
||||||
|
|
@ -114,10 +121,12 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var link = linkGenerator.GetLink(
|
var link = linkGenerator.GetLink(
|
||||||
httpContext: null,
|
new LinkGeneratorContext
|
||||||
new[] { endpoint1, endpoint2, endpoint3 },
|
{
|
||||||
context.ExplicitValues,
|
Endpoints = new[] { endpoint1, endpoint2, endpoint3 },
|
||||||
context.AmbientValues);
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("/Home/Index", link);
|
Assert.Equal("/Home/Index", link);
|
||||||
|
|
@ -135,10 +144,12 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var link = linkGenerator.GetLink(
|
var link = linkGenerator.GetLink(
|
||||||
httpContext: null,
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
Endpoints = new[] { endpoint },
|
||||||
context.AmbientValues);
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("/Home/Index?name=name%20with%20%25special%20%23characters", link);
|
Assert.Equal("/Home/Index?name=name%20with%20%25special%20%23characters", link);
|
||||||
|
|
@ -156,10 +167,12 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var link = linkGenerator.GetLink(
|
var link = linkGenerator.GetLink(
|
||||||
httpContext: null,
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
Endpoints = new[] { endpoint },
|
||||||
context.AmbientValues);
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("/Home/Index?color=red&color=green&color=blue", link);
|
Assert.Equal("/Home/Index?color=red&color=green&color=blue", link);
|
||||||
|
|
@ -177,10 +190,12 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var link = linkGenerator.GetLink(
|
var link = linkGenerator.GetLink(
|
||||||
httpContext: null,
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
Endpoints = new[] { endpoint },
|
||||||
context.AmbientValues);
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("/Home/Index?items=10&items=20&items=30", link);
|
Assert.Equal("/Home/Index?items=10&items=20&items=30", link);
|
||||||
|
|
@ -198,10 +213,12 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var link = linkGenerator.GetLink(
|
var link = linkGenerator.GetLink(
|
||||||
httpContext: null,
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
Endpoints = new[] { endpoint },
|
||||||
context.AmbientValues);
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("/Home/Index", link);
|
Assert.Equal("/Home/Index", link);
|
||||||
|
|
@ -219,10 +236,12 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var link = linkGenerator.GetLink(
|
var link = linkGenerator.GetLink(
|
||||||
httpContext: null,
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
Endpoints = new[] { endpoint },
|
||||||
context.AmbientValues);
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("/Home/Index?page=1&color=red&color=green&color=blue&message=textfortest", link);
|
Assert.Equal("/Home/Index?page=1&color=red&color=green&color=blue&message=textfortest", link);
|
||||||
|
|
@ -240,15 +259,259 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var link = linkGenerator.GetLink(
|
var link = linkGenerator.GetLink(
|
||||||
httpContext: null,
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
Endpoints = new[] { endpoint },
|
||||||
context.AmbientValues);
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("/Home/Index", link);
|
Assert.Equal("/Home/Index", link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetLink_GeneratesLowercaseUrl_SetOnRouteOptions()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var endpoint = CreateEndpoint("{controller}/{action}");
|
||||||
|
var linkGenerator = CreateLinkGenerator(new RouteOptions() { LowercaseUrls = true });
|
||||||
|
var context = CreateRouteValuesContext(
|
||||||
|
suppliedValues: new { action = "Index" },
|
||||||
|
ambientValues: new { controller = "Home" });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var link = linkGenerator.GetLink(
|
||||||
|
new LinkGeneratorContext
|
||||||
|
{
|
||||||
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("/home/index", link);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetLink_GeneratesLowercaseQueryString_SetOnRouteOptions()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var endpoint = CreateEndpoint("{controller}/{action}");
|
||||||
|
var linkGenerator = CreateLinkGenerator(
|
||||||
|
new RouteOptions() { LowercaseUrls = true, LowercaseQueryStrings = true });
|
||||||
|
var context = CreateRouteValuesContext(
|
||||||
|
suppliedValues: new { action = "Index", ShowStatus = "True", INFO = "DETAILED" },
|
||||||
|
ambientValues: new { controller = "Home" });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var link = linkGenerator.GetLink(
|
||||||
|
new LinkGeneratorContext
|
||||||
|
{
|
||||||
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("/home/index?showstatus=true&info=detailed", link);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetLink_GeneratesLowercaseQueryString_OnlyIfLowercaseUrlIsTrue_SetOnRouteOptions()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var endpoint = CreateEndpoint("{controller}/{action}");
|
||||||
|
var linkGenerator = CreateLinkGenerator(
|
||||||
|
new RouteOptions() { LowercaseUrls = false, LowercaseQueryStrings = true });
|
||||||
|
var context = CreateRouteValuesContext(
|
||||||
|
suppliedValues: new { action = "Index", ShowStatus = "True", INFO = "DETAILED" },
|
||||||
|
ambientValues: new { controller = "Home" });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var link = linkGenerator.GetLink(
|
||||||
|
new LinkGeneratorContext
|
||||||
|
{
|
||||||
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("/Home/Index?ShowStatus=True&INFO=DETAILED", link);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetLink_AppendsTrailingSlash_SetOnRouteOptions()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var endpoint = CreateEndpoint("{controller}/{action}");
|
||||||
|
var linkGenerator = CreateLinkGenerator(new RouteOptions() { AppendTrailingSlash = true });
|
||||||
|
var context = CreateRouteValuesContext(
|
||||||
|
suppliedValues: new { action = "Index" },
|
||||||
|
ambientValues: new { controller = "Home" });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var link = linkGenerator.GetLink(
|
||||||
|
new LinkGeneratorContext
|
||||||
|
{
|
||||||
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("/Home/Index/", link);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetLink_GeneratesLowercaseQueryStringAndTrailingSlash_SetOnRouteOptions()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var endpoint = CreateEndpoint("{controller}/{action}");
|
||||||
|
var linkGenerator = CreateLinkGenerator(
|
||||||
|
new RouteOptions() { LowercaseUrls = true, LowercaseQueryStrings = true, AppendTrailingSlash = true });
|
||||||
|
var context = CreateRouteValuesContext(
|
||||||
|
suppliedValues: new { action = "Index", ShowStatus = "True", INFO = "DETAILED" },
|
||||||
|
ambientValues: new { controller = "Home" });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var link = linkGenerator.GetLink(
|
||||||
|
new LinkGeneratorContext
|
||||||
|
{
|
||||||
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("/home/index/?showstatus=true&info=detailed", link);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetLink_LowercaseUrlSetToTrue_OnRouteOptions_OverridenByCallsiteValue()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var endpoint = CreateEndpoint("{controller}/{action}");
|
||||||
|
var linkGenerator = CreateLinkGenerator(new RouteOptions() { LowercaseUrls = true });
|
||||||
|
var context = CreateRouteValuesContext(
|
||||||
|
suppliedValues: new { action = "InDex" },
|
||||||
|
ambientValues: new { controller = "HoMe" });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var link = linkGenerator.GetLink(
|
||||||
|
new LinkGeneratorContext
|
||||||
|
{
|
||||||
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues,
|
||||||
|
LowercaseUrls = false
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("/HoMe/InDex", link);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetLink_LowercaseUrlSetToFalse_OnRouteOptions_OverridenByCallsiteValue()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var endpoint = CreateEndpoint("{controller}/{action}");
|
||||||
|
var linkGenerator = CreateLinkGenerator(new RouteOptions() { LowercaseUrls = false });
|
||||||
|
var context = CreateRouteValuesContext(
|
||||||
|
suppliedValues: new { action = "InDex" },
|
||||||
|
ambientValues: new { controller = "HoMe" });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var link = linkGenerator.GetLink(
|
||||||
|
new LinkGeneratorContext
|
||||||
|
{
|
||||||
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues,
|
||||||
|
LowercaseUrls = true
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("/home/index", link);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetLink_LowercaseUrlQueryStringsSetToTrue_OnRouteOptions_OverridenByCallsiteValue()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var endpoint = CreateEndpoint("{controller}/{action}");
|
||||||
|
var linkGenerator = CreateLinkGenerator(
|
||||||
|
new RouteOptions() { LowercaseUrls = true, LowercaseQueryStrings = true });
|
||||||
|
var context = CreateRouteValuesContext(
|
||||||
|
suppliedValues: new { action = "Index", ShowStatus = "True", INFO = "DETAILED" },
|
||||||
|
ambientValues: new { controller = "Home" });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var link = linkGenerator.GetLink(
|
||||||
|
new LinkGeneratorContext
|
||||||
|
{
|
||||||
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues,
|
||||||
|
LowercaseUrls = false,
|
||||||
|
LowercaseQueryStrings = false
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("/Home/Index?ShowStatus=True&INFO=DETAILED", link);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetLink_LowercaseUrlQueryStringsSetToFalse_OnRouteOptions_OverridenByCallsiteValue()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var endpoint = CreateEndpoint("{controller}/{action}");
|
||||||
|
var linkGenerator = CreateLinkGenerator(
|
||||||
|
new RouteOptions() { LowercaseUrls = false, LowercaseQueryStrings = false });
|
||||||
|
var context = CreateRouteValuesContext(
|
||||||
|
suppliedValues: new { action = "Index", ShowStatus = "True", INFO = "DETAILED" },
|
||||||
|
ambientValues: new { controller = "Home" });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var link = linkGenerator.GetLink(
|
||||||
|
new LinkGeneratorContext
|
||||||
|
{
|
||||||
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues,
|
||||||
|
LowercaseUrls = true,
|
||||||
|
LowercaseQueryStrings = true
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("/home/index?showstatus=true&info=detailed", link);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetLink_AppendTrailingSlashSetToFalse_OnRouteOptions_OverridenByCallsiteValue()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var endpoint = CreateEndpoint("{controller}/{action}");
|
||||||
|
var linkGenerator = CreateLinkGenerator(new RouteOptions() { AppendTrailingSlash = false });
|
||||||
|
var context = CreateRouteValuesContext(
|
||||||
|
suppliedValues: new { action = "Index" },
|
||||||
|
ambientValues: new { controller = "Home" });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var link = linkGenerator.GetLink(
|
||||||
|
new LinkGeneratorContext
|
||||||
|
{
|
||||||
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues,
|
||||||
|
AppendTrailingSlash = true
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("/Home/Index/", link);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void RouteGenerationRejectsConstraints()
|
public void RouteGenerationRejectsConstraints()
|
||||||
{
|
{
|
||||||
|
|
@ -263,10 +526,13 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var canGenerateLink = linkGenerator.TryGetLink(
|
var canGenerateLink = linkGenerator.TryGetLink(
|
||||||
new DefaultHttpContext(),
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
HttpContext = new DefaultHttpContext(),
|
||||||
context.AmbientValues,
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
},
|
||||||
out var link);
|
out var link);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
@ -287,10 +553,13 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var canGenerateLink = linkGenerator.TryGetLink(
|
var canGenerateLink = linkGenerator.TryGetLink(
|
||||||
new DefaultHttpContext(),
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
HttpContext = new DefaultHttpContext(),
|
||||||
context.AmbientValues,
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
},
|
||||||
out var link);
|
out var link);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
@ -312,10 +581,13 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var canGenerateLink = linkGenerator.TryGetLink(
|
var canGenerateLink = linkGenerator.TryGetLink(
|
||||||
new DefaultHttpContext(),
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
HttpContext = new DefaultHttpContext(),
|
||||||
context.AmbientValues,
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
},
|
||||||
out var link);
|
out var link);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
@ -336,10 +608,13 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var canGenerateLink = linkGenerator.TryGetLink(
|
var canGenerateLink = linkGenerator.TryGetLink(
|
||||||
new DefaultHttpContext(),
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
HttpContext = new DefaultHttpContext(),
|
||||||
context.AmbientValues,
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
},
|
||||||
out var link);
|
out var link);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
@ -372,10 +647,13 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var canGenerateLink = linkGenerator.TryGetLink(
|
var canGenerateLink = linkGenerator.TryGetLink(
|
||||||
new DefaultHttpContext(),
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
HttpContext = new DefaultHttpContext(),
|
||||||
context.AmbientValues,
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
},
|
||||||
out var link);
|
out var link);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
@ -406,10 +684,13 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var canGenerateLink = linkGenerator.TryGetLink(
|
var canGenerateLink = linkGenerator.TryGetLink(
|
||||||
new DefaultHttpContext(),
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
HttpContext = new DefaultHttpContext(),
|
||||||
context.AmbientValues,
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
},
|
||||||
out var link);
|
out var link);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
@ -440,10 +721,13 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var link = linkGenerator.GetLink(
|
var link = linkGenerator.GetLink(
|
||||||
new DefaultHttpContext(),
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
HttpContext = new DefaultHttpContext(),
|
||||||
context.AmbientValues);
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("/slug/Home/Store", link);
|
Assert.Equal("/slug/Home/Store", link);
|
||||||
|
|
@ -471,10 +755,13 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var link = linkGenerator.GetLink(
|
var link = linkGenerator.GetLink(
|
||||||
new DefaultHttpContext(),
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
HttpContext = new DefaultHttpContext(),
|
||||||
context.AmbientValues);
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("/slug/Shopping", link);
|
Assert.Equal("/slug/Shopping", link);
|
||||||
|
|
@ -503,10 +790,13 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var link = linkGenerator.GetLink(
|
var link = linkGenerator.GetLink(
|
||||||
new DefaultHttpContext(),
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
HttpContext = new DefaultHttpContext(),
|
||||||
context.AmbientValues);
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("/slug/Home/Store", link);
|
Assert.Equal("/slug/Home/Store", link);
|
||||||
|
|
@ -528,10 +818,13 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var link = linkGenerator.GetLink(
|
var link = linkGenerator.GetLink(
|
||||||
new DefaultHttpContext(),
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
HttpContext = new DefaultHttpContext(),
|
||||||
context.AmbientValues);
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("/Home/Index/4", link);
|
Assert.Equal("/Home/Index/4", link);
|
||||||
|
|
@ -545,17 +838,20 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
var endpoint = CreateEndpoint(
|
var endpoint = CreateEndpoint(
|
||||||
template: "Home/Index/{id}",
|
template: "Home/Index/{id}",
|
||||||
defaults: new { controller = "Home", action = "Index" },
|
defaults: new { controller = "Home", action = "Index" },
|
||||||
constraints: new {id = "int"});
|
constraints: new { id = "int" });
|
||||||
|
|
||||||
var context = CreateRouteValuesContext(
|
var context = CreateRouteValuesContext(
|
||||||
suppliedValues: new { action = "Index", controller = "Home", id = "not-an-integer" });
|
suppliedValues: new { action = "Index", controller = "Home", id = "not-an-integer" });
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var canGenerateLink = linkGenerator.TryGetLink(
|
var canGenerateLink = linkGenerator.TryGetLink(
|
||||||
new DefaultHttpContext(),
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
HttpContext = new DefaultHttpContext(),
|
||||||
context.AmbientValues,
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
},
|
||||||
out var link);
|
out var link);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
@ -576,10 +872,13 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var link = linkGenerator.GetLink(
|
var link = linkGenerator.GetLink(
|
||||||
new DefaultHttpContext(),
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
HttpContext = new DefaultHttpContext(),
|
||||||
context.AmbientValues);
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("/Home/Index/98", link);
|
Assert.Equal("/Home/Index/98", link);
|
||||||
|
|
@ -600,10 +899,13 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var link = linkGenerator.GetLink(
|
var link = linkGenerator.GetLink(
|
||||||
new DefaultHttpContext(),
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
HttpContext = new DefaultHttpContext(),
|
||||||
context.AmbientValues);
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("/Home/Index", link);
|
Assert.Equal("/Home/Index", link);
|
||||||
|
|
@ -624,10 +926,13 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var canGenerateLink = linkGenerator.TryGetLink(
|
var canGenerateLink = linkGenerator.TryGetLink(
|
||||||
new DefaultHttpContext(),
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
HttpContext = new DefaultHttpContext(),
|
||||||
context.AmbientValues,
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
},
|
||||||
out var link);
|
out var link);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
@ -649,10 +954,13 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var link = linkGenerator.GetLink(
|
var link = linkGenerator.GetLink(
|
||||||
new DefaultHttpContext(),
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
HttpContext = new DefaultHttpContext(),
|
||||||
context.AmbientValues);
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("/Home/Index/14", link);
|
Assert.Equal("/Home/Index/14", link);
|
||||||
|
|
@ -673,10 +981,13 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var canGenerateLink = linkGenerator.TryGetLink(
|
var canGenerateLink = linkGenerator.TryGetLink(
|
||||||
new DefaultHttpContext(),
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
HttpContext = new DefaultHttpContext(),
|
||||||
context.AmbientValues,
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
},
|
||||||
out var link);
|
out var link);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
@ -699,10 +1010,13 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var link = linkGenerator.GetLink(
|
var link = linkGenerator.GetLink(
|
||||||
new DefaultHttpContext(),
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
HttpContext = new DefaultHttpContext(),
|
||||||
context.AmbientValues);
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("/Home/Index/products", link);
|
Assert.Equal("/Home/Index/products", link);
|
||||||
|
|
@ -719,10 +1033,12 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var link = linkGenerator.GetLink(
|
var link = linkGenerator.GetLink(
|
||||||
httpContext: null,
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
Endpoints = new[] { endpoint },
|
||||||
context.AmbientValues);
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("/Home/Index/products", link);
|
Assert.Equal("/Home/Index/products", link);
|
||||||
|
|
@ -739,10 +1055,60 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var link = linkGenerator.GetLink(
|
var link = linkGenerator.GetLink(
|
||||||
httpContext: null,
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
Endpoints = new[] { endpoint },
|
||||||
context.AmbientValues);
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("/Home/Index", link);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetLink_OptionalParameter_ParameterPresentInValuesAndDefaults()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var endpoint = CreateEndpoint(
|
||||||
|
template: "{controller}/{action}/{name}",
|
||||||
|
defaults: new { name = "default-products" });
|
||||||
|
var linkGenerator = CreateLinkGenerator();
|
||||||
|
var context = CreateRouteValuesContext(
|
||||||
|
suppliedValues: new { action = "Index", controller = "Home", name = "products" });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var link = linkGenerator.GetLink(
|
||||||
|
new LinkGeneratorContext
|
||||||
|
{
|
||||||
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("/Home/Index/products", link);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetLink_OptionalParameter_ParameterNotPresentInValues_PresentInDefaults()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var endpoint = CreateEndpoint(
|
||||||
|
template: "{controller}/{action}/{name}",
|
||||||
|
defaults: new { name = "products" });
|
||||||
|
var linkGenerator = CreateLinkGenerator();
|
||||||
|
var context = CreateRouteValuesContext(
|
||||||
|
suppliedValues: new { action = "Index", controller = "Home" });
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var link = linkGenerator.GetLink(
|
||||||
|
new LinkGeneratorContext
|
||||||
|
{
|
||||||
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("/Home/Index", link);
|
Assert.Equal("/Home/Index", link);
|
||||||
|
|
@ -759,10 +1125,12 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var link = linkGenerator.GetLink(
|
var link = linkGenerator.GetLink(
|
||||||
httpContext: null,
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
Endpoints = new[] { endpoint },
|
||||||
context.AmbientValues);
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("/Home/Index/products?format=json", link);
|
Assert.Equal("/Home/Index/products?format=json", link);
|
||||||
|
|
@ -781,10 +1149,13 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var link = linkGenerator.GetLink(
|
var link = linkGenerator.GetLink(
|
||||||
new DefaultHttpContext(),
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
HttpContext = new DefaultHttpContext(),
|
||||||
context.AmbientValues);
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("/Home/Index/.products", link);
|
Assert.Equal("/Home/Index/.products", link);
|
||||||
|
|
@ -802,10 +1173,13 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var link = linkGenerator.GetLink(
|
var link = linkGenerator.GetLink(
|
||||||
new DefaultHttpContext(),
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
HttpContext = new DefaultHttpContext(),
|
||||||
context.AmbientValues);
|
Endpoints = new[] { endpoint },
|
||||||
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("/Home/Index/", link);
|
Assert.Equal("/Home/Index/", link);
|
||||||
|
|
@ -822,10 +1196,12 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var link = linkGenerator.GetLink(
|
var link = linkGenerator.GetLink(
|
||||||
httpContext: null,
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
Endpoints = new[] { endpoint },
|
||||||
context.AmbientValues);
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("/Home/Index", link);
|
Assert.Equal("/Home/Index", link);
|
||||||
|
|
@ -843,10 +1219,12 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var link = linkGenerator.GetLink(
|
var link = linkGenerator.GetLink(
|
||||||
httpContext: null,
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
Endpoints = new[] { endpoint },
|
||||||
context.AmbientValues);
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("/a/15/17", link);
|
Assert.Equal("/a/15/17", link);
|
||||||
|
|
@ -864,10 +1242,12 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var link = linkGenerator.GetLink(
|
var link = linkGenerator.GetLink(
|
||||||
httpContext: null,
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
Endpoints = new[] { endpoint },
|
||||||
context.AmbientValues);
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("/a/15/17", link);
|
Assert.Equal("/a/15/17", link);
|
||||||
|
|
@ -885,10 +1265,12 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var link = linkGenerator.GetLink(
|
var link = linkGenerator.GetLink(
|
||||||
httpContext: null,
|
new LinkGeneratorContext
|
||||||
new[] { endpoint },
|
{
|
||||||
context.ExplicitValues,
|
Endpoints = new[] { endpoint },
|
||||||
context.AmbientValues);
|
ExplicitValues = context.ExplicitValues,
|
||||||
|
AmbientValues = context.AmbientValues
|
||||||
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal("/a", link);
|
Assert.Equal("/a", link);
|
||||||
|
|
@ -904,7 +1286,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
private MatcherEndpoint CreateEndpoint(
|
private MatcherEndpoint CreateEndpoint(
|
||||||
string template,
|
string template,
|
||||||
object defaults = null,
|
object defaults = null,
|
||||||
object constraints = null,
|
object constraints = null,
|
||||||
int order = 0,
|
int order = 0,
|
||||||
EndpointMetadataCollection metadata = null)
|
EndpointMetadataCollection metadata = null)
|
||||||
|
|
@ -918,13 +1300,16 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LinkGenerator CreateLinkGenerator()
|
private LinkGenerator CreateLinkGenerator(RouteOptions routeOptions = null)
|
||||||
{
|
{
|
||||||
|
routeOptions = routeOptions ?? new RouteOptions();
|
||||||
|
var options = Options.Create(routeOptions);
|
||||||
return new DefaultLinkGenerator(
|
return new DefaultLinkGenerator(
|
||||||
new DefaultMatchProcessorFactory(
|
new DefaultMatchProcessorFactory(
|
||||||
Options.Create(new RouteOptions()),
|
options,
|
||||||
Mock.Of<IServiceProvider>()),
|
Mock.Of<IServiceProvider>()),
|
||||||
new DefaultObjectPool<UriBuildingContext>(new UriBuilderContextPooledObjectPolicy()),
|
new DefaultObjectPool<UriBuildingContext>(new UriBuilderContextPooledObjectPolicy()),
|
||||||
|
options,
|
||||||
NullLogger<DefaultLinkGenerator>.Instance);
|
NullLogger<DefaultLinkGenerator>.Instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Routing.EndpointFinders;
|
||||||
using Microsoft.AspNetCore.Routing.Internal;
|
using Microsoft.AspNetCore.Routing.Internal;
|
||||||
using Microsoft.AspNetCore.Routing.Matchers;
|
using Microsoft.AspNetCore.Routing.Matchers;
|
||||||
using Microsoft.AspNetCore.Routing.Patterns;
|
using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
|
|
@ -33,7 +34,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
Assert.NotNull(finder.NamedMatches);
|
Assert.NotNull(finder.NamedMatches);
|
||||||
Assert.True(finder.NamedMatches.TryGetValue("named", out var namedMatches));
|
Assert.True(finder.NamedMatches.TryGetValue("named", out var namedMatches));
|
||||||
var namedMatch = Assert.Single(namedMatches);
|
var namedMatch = Assert.Single(namedMatches);
|
||||||
var actual = Assert.IsType<MatcherEndpoint>(namedMatch.Entry.Data);
|
var actual = Assert.IsType<MatcherEndpoint>(namedMatch.Match.Entry.Data);
|
||||||
Assert.Same(endpoint2, actual);
|
Assert.Same(endpoint2, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -54,8 +55,8 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
Assert.NotNull(finder.NamedMatches);
|
Assert.NotNull(finder.NamedMatches);
|
||||||
Assert.True(finder.NamedMatches.TryGetValue("named", out var namedMatches));
|
Assert.True(finder.NamedMatches.TryGetValue("named", out var namedMatches));
|
||||||
Assert.Equal(2, namedMatches.Count);
|
Assert.Equal(2, namedMatches.Count);
|
||||||
Assert.Same(endpoint2, Assert.IsType<MatcherEndpoint>(namedMatches[0].Entry.Data));
|
Assert.Same(endpoint2, Assert.IsType<MatcherEndpoint>(namedMatches[0].Match.Entry.Data));
|
||||||
Assert.Same(endpoint3, Assert.IsType<MatcherEndpoint>(namedMatches[1].Entry.Data));
|
Assert.Same(endpoint3, Assert.IsType<MatcherEndpoint>(namedMatches[1].Match.Entry.Data));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -75,8 +76,8 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
Assert.NotNull(finder.NamedMatches);
|
Assert.NotNull(finder.NamedMatches);
|
||||||
Assert.True(finder.NamedMatches.TryGetValue("named", out var namedMatches));
|
Assert.True(finder.NamedMatches.TryGetValue("named", out var namedMatches));
|
||||||
Assert.Equal(2, namedMatches.Count);
|
Assert.Equal(2, namedMatches.Count);
|
||||||
Assert.Same(endpoint2, Assert.IsType<MatcherEndpoint>(namedMatches[0].Entry.Data));
|
Assert.Same(endpoint2, Assert.IsType<MatcherEndpoint>(namedMatches[0].Match.Entry.Data));
|
||||||
Assert.Same(endpoint3, Assert.IsType<MatcherEndpoint>(namedMatches[1].Entry.Data));
|
Assert.Same(endpoint3, Assert.IsType<MatcherEndpoint>(namedMatches[1].Match.Entry.Data));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -98,7 +99,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
Assert.NotNull(finder.NamedMatches);
|
Assert.NotNull(finder.NamedMatches);
|
||||||
Assert.True(finder.NamedMatches.TryGetValue("named", out var namedMatches));
|
Assert.True(finder.NamedMatches.TryGetValue("named", out var namedMatches));
|
||||||
var namedMatch = Assert.Single(namedMatches);
|
var namedMatch = Assert.Single(namedMatches);
|
||||||
var actual = Assert.IsType<MatcherEndpoint>(namedMatch.Entry.Data);
|
var actual = Assert.IsType<MatcherEndpoint>(namedMatch.Match.Entry.Data);
|
||||||
Assert.Same(endpoint2, actual);
|
Assert.Same(endpoint2, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -169,6 +170,60 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FindEndpoints_ReturnsEndpoint_WhenLookedUpByRouteName()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expected = CreateEndpoint(
|
||||||
|
"api/orders/{id}",
|
||||||
|
defaults: new { controller = "Orders", action = "GetById" },
|
||||||
|
requiredValues: new { controller = "Orders", action = "GetById" },
|
||||||
|
routeName: "OrdersApi");
|
||||||
|
var finder = CreateEndpointFinder(expected);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var foundEndpoints = finder.FindEndpoints(
|
||||||
|
new RouteValuesBasedEndpointFinderContext
|
||||||
|
{
|
||||||
|
ExplicitValues = new RouteValueDictionary(new { id = 10 }),
|
||||||
|
AmbientValues = new RouteValueDictionary(new { controller = "Home", action = "Index" }),
|
||||||
|
RouteName = "OrdersApi"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var actual = Assert.Single(foundEndpoints);
|
||||||
|
Assert.Same(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FindEndpoints_AlwaysReturnsEndpointsByRouteName_IgnoringMissingRequiredParameterValues()
|
||||||
|
{
|
||||||
|
// Here 'id' is the required value. The endpoint finder would always return an endpoint by looking up
|
||||||
|
// name only. Its the link generator which uses these endpoints finally to generate a link or not
|
||||||
|
// based on the required parameter values being present or not.
|
||||||
|
|
||||||
|
// Arrange
|
||||||
|
var expected = CreateEndpoint(
|
||||||
|
"api/orders/{id}",
|
||||||
|
defaults: new { controller = "Orders", action = "GetById" },
|
||||||
|
requiredValues: new { controller = "Orders", action = "GetById" },
|
||||||
|
routeName: "OrdersApi");
|
||||||
|
var finder = CreateEndpointFinder(expected);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var foundEndpoints = finder.FindEndpoints(
|
||||||
|
new RouteValuesBasedEndpointFinderContext
|
||||||
|
{
|
||||||
|
ExplicitValues = new RouteValueDictionary(),
|
||||||
|
AmbientValues = new RouteValueDictionary(),
|
||||||
|
RouteName = "OrdersApi"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var actual = Assert.Single(foundEndpoints);
|
||||||
|
Assert.Same(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
private CustomRouteValuesBasedEndpointFinder CreateEndpointFinder(params Endpoint[] endpoints)
|
private CustomRouteValuesBasedEndpointFinder CreateEndpointFinder(params Endpoint[] endpoints)
|
||||||
{
|
{
|
||||||
return CreateEndpointFinder(new DefaultEndpointDataSource(endpoints));
|
return CreateEndpointFinder(new DefaultEndpointDataSource(endpoints));
|
||||||
|
|
@ -239,9 +294,9 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
public IEnumerable<OutboundMatch> AllMatches { get; private set; }
|
public IEnumerable<OutboundMatch> AllMatches { get; private set; }
|
||||||
|
|
||||||
public IDictionary<string, List<OutboundMatch>> NamedMatches { get; private set; }
|
public IDictionary<string, List<OutboundMatchResult>> NamedMatches { get; private set; }
|
||||||
|
|
||||||
protected override (IEnumerable<OutboundMatch>, IDictionary<string, List<OutboundMatch>>) GetOutboundMatches()
|
protected override (IEnumerable<OutboundMatch>, IDictionary<string, List<OutboundMatchResult>>) GetOutboundMatches()
|
||||||
{
|
{
|
||||||
var matches = base.GetOutboundMatches();
|
var matches = base.GetOutboundMatches();
|
||||||
AllMatches = matches.Item1;
|
AllMatches = matches.Item1;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue