Added a RouteValuesBasedEndpointFinder
This commit is contained in:
parent
bc5f02444b
commit
1009705283
|
|
@ -32,11 +32,11 @@ namespace Benchmarks
|
|||
return response.Body.WriteAsync(_helloWorldPayload, 0, payloadLength);
|
||||
},
|
||||
template: "/plaintext",
|
||||
values: new { },
|
||||
defaults: new RouteValueDictionary(),
|
||||
requiredValues: new RouteValueDictionary(),
|
||||
order: 0,
|
||||
metadata: EndpointMetadataCollection.Empty,
|
||||
displayName: "Plaintext",
|
||||
address: null),
|
||||
displayName: "Plaintext"),
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,11 +28,11 @@ namespace Microsoft.AspNetCore.Routing.Matchers
|
|||
return new MatcherEndpoint(
|
||||
(next) => (context) => Task.CompletedTask,
|
||||
template,
|
||||
new { },
|
||||
new RouteValueDictionary(),
|
||||
new RouteValueDictionary(),
|
||||
0,
|
||||
EndpointMetadataCollection.Empty,
|
||||
template,
|
||||
address: null);
|
||||
template);
|
||||
}
|
||||
|
||||
internal static int[] SampleRequests(int endpointCount, int count)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ namespace DispatcherSample.Web
|
|||
response.ContentLength = payloadLength;
|
||||
return response.Body.WriteAsync(_homePayload, 0, payloadLength);
|
||||
},
|
||||
"/", new { }, 0, EndpointMetadataCollection.Empty, "Home", address: null),
|
||||
"/", new RouteValueDictionary(), new RouteValueDictionary(), 0, EndpointMetadataCollection.Empty, "Home"),
|
||||
new MatcherEndpoint((next) => (httpContext) =>
|
||||
{
|
||||
var response = httpContext.Response;
|
||||
|
|
@ -41,7 +41,7 @@ namespace DispatcherSample.Web
|
|||
response.ContentLength = payloadLength;
|
||||
return response.Body.WriteAsync(_helloWorldPayload, 0, payloadLength);
|
||||
},
|
||||
"/plaintext", new { }, 0, EndpointMetadataCollection.Empty, "Plaintext", address: null),
|
||||
"/plaintext", new RouteValueDictionary(), new RouteValueDictionary(), 0, EndpointMetadataCollection.Empty, "Plaintext"),
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,19 +10,15 @@ namespace Microsoft.AspNetCore.Routing
|
|||
{
|
||||
protected Endpoint(
|
||||
EndpointMetadataCollection metadata,
|
||||
string displayName,
|
||||
Address address)
|
||||
string displayName)
|
||||
{
|
||||
// All are allowed to be null
|
||||
Metadata = metadata ?? EndpointMetadataCollection.Empty;
|
||||
DisplayName = displayName;
|
||||
Address = address;
|
||||
}
|
||||
|
||||
public string DisplayName { get; }
|
||||
|
||||
public EndpointMetadataCollection Metadata { get; }
|
||||
|
||||
public Address Address { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Microsoft.AspNetCore.Routing
|
||||
{
|
||||
public interface IEndpointFinder
|
||||
public interface IEndpointFinder<TAddress>
|
||||
{
|
||||
IEnumerable<Endpoint> FindEndpoints(Address address);
|
||||
IEnumerable<Endpoint> FindEndpoints(TAddress address);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,21 @@
|
|||
// 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;
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing
|
||||
{
|
||||
public interface ILinkGenerator
|
||||
{
|
||||
bool TryGetLink(LinkGeneratorContext context, out string link);
|
||||
bool TryGetLink(
|
||||
IEnumerable<Endpoint> endpoints,
|
||||
RouteValueDictionary explicitValues,
|
||||
RouteValueDictionary ambientValues,
|
||||
out string link);
|
||||
|
||||
string GetLink(LinkGeneratorContext context);
|
||||
string GetLink(
|
||||
IEnumerable<Endpoint> endpoints,
|
||||
RouteValueDictionary explicitValues,
|
||||
RouteValueDictionary ambientValues);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,11 @@
|
|||
// 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
|
||||
{
|
||||
public class Address
|
||||
public interface INameMetadata
|
||||
{
|
||||
public Address()
|
||||
{
|
||||
}
|
||||
|
||||
public Address(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
string Name { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// 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
|
||||
{
|
||||
public interface IRouteNameMetadata
|
||||
{
|
||||
string Name { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing
|
||||
{
|
||||
internal class DefaultEndpointFinder : IEndpointFinder
|
||||
{
|
||||
private readonly CompositeEndpointDataSource _endpointDatasource;
|
||||
private readonly ILogger<DefaultEndpointFinder> _logger;
|
||||
|
||||
public DefaultEndpointFinder(
|
||||
CompositeEndpointDataSource endpointDataSource,
|
||||
ILogger<DefaultEndpointFinder> logger)
|
||||
{
|
||||
_endpointDatasource = endpointDataSource;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public IEnumerable<Endpoint> FindEndpoints(Address lookupAddress)
|
||||
{
|
||||
var allEndpoints = _endpointDatasource.Endpoints;
|
||||
|
||||
if (lookupAddress == null || string.IsNullOrEmpty(lookupAddress.Name))
|
||||
{
|
||||
return allEndpoints;
|
||||
}
|
||||
|
||||
var endpointsWithAddress = allEndpoints.Where(ep => ep.Address != null);
|
||||
if (!endpointsWithAddress.Any())
|
||||
{
|
||||
return allEndpoints;
|
||||
}
|
||||
|
||||
foreach (var endpoint in endpointsWithAddress)
|
||||
{
|
||||
if (string.Equals(lookupAddress.Name, endpoint.Address.Name, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return new[] { endpoint };
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogDebug(
|
||||
$"Could not find an endpoint having an address with name '{lookupAddress.Name}'.");
|
||||
|
||||
return Enumerable.Empty<Endpoint>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -15,23 +15,23 @@ namespace Microsoft.AspNetCore.Routing
|
|||
{
|
||||
public class DefaultLinkGenerator : ILinkGenerator
|
||||
{
|
||||
private readonly IEndpointFinder _endpointFinder;
|
||||
private readonly ObjectPool<UriBuildingContext> _uriBuildingContextPool;
|
||||
private readonly ILogger<DefaultLinkGenerator> _logger;
|
||||
|
||||
public DefaultLinkGenerator(
|
||||
IEndpointFinder endpointFinder,
|
||||
ObjectPool<UriBuildingContext> uriBuildingContextPool,
|
||||
ILogger<DefaultLinkGenerator> logger)
|
||||
{
|
||||
_endpointFinder = endpointFinder;
|
||||
_uriBuildingContextPool = uriBuildingContextPool;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public string GetLink(LinkGeneratorContext context)
|
||||
public string GetLink(
|
||||
IEnumerable<Endpoint> endpoints,
|
||||
RouteValueDictionary explicitValues,
|
||||
RouteValueDictionary ambientValues)
|
||||
{
|
||||
if (TryGetLink(context, out var link))
|
||||
if (TryGetLink(endpoints, explicitValues, ambientValues, out var link))
|
||||
{
|
||||
return link;
|
||||
}
|
||||
|
|
@ -39,10 +39,12 @@ namespace Microsoft.AspNetCore.Routing
|
|||
throw new InvalidOperationException("Could not find a matching endpoint to generate a link.");
|
||||
}
|
||||
|
||||
public bool TryGetLink(LinkGeneratorContext context, out string link)
|
||||
public bool TryGetLink(
|
||||
IEnumerable<Endpoint> endpoints,
|
||||
RouteValueDictionary explicitValues,
|
||||
RouteValueDictionary ambientValues,
|
||||
out string link)
|
||||
{
|
||||
var address = context.Address;
|
||||
var endpoints = _endpointFinder.FindEndpoints(address);
|
||||
link = null;
|
||||
|
||||
if (endpoints == null)
|
||||
|
|
@ -59,7 +61,7 @@ namespace Microsoft.AspNetCore.Routing
|
|||
|
||||
foreach (var endpoint in matcherEndpoints)
|
||||
{
|
||||
link = GetLink(endpoint.ParsedTemlate, endpoint.Values, context);
|
||||
link = GetLink(endpoint.ParsedTemplate, endpoint.Defaults, explicitValues, ambientValues);
|
||||
if (link != null)
|
||||
{
|
||||
return true;
|
||||
|
|
@ -71,19 +73,17 @@ namespace Microsoft.AspNetCore.Routing
|
|||
|
||||
private string GetLink(
|
||||
RouteTemplate template,
|
||||
IReadOnlyDictionary<string, object> defaultValues,
|
||||
LinkGeneratorContext context)
|
||||
RouteValueDictionary defaults,
|
||||
RouteValueDictionary explicitValues,
|
||||
RouteValueDictionary ambientValues)
|
||||
{
|
||||
var defaults = new RouteValueDictionary(defaultValues);
|
||||
var templateBinder = new TemplateBinder(
|
||||
UrlEncoder.Default,
|
||||
_uriBuildingContextPool,
|
||||
template,
|
||||
defaults);
|
||||
|
||||
var values = templateBinder.GetValues(
|
||||
new RouteValueDictionary(context.AmbientValues),
|
||||
new RouteValueDictionary(context.SuppliedValues));
|
||||
var values = templateBinder.GetValues(ambientValues, explicitValues);
|
||||
if (values == null)
|
||||
{
|
||||
// We're missing one of the required values for this route.
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.Routing.EndpointConstraints;
|
||||
using Microsoft.AspNetCore.Routing.EndpointFinders;
|
||||
using Microsoft.AspNetCore.Routing.Matchers;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
|
@ -35,7 +37,8 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
services.TryAddSingleton<MatcherFactory, TreeMatcherFactory>();
|
||||
|
||||
// Link generation related services
|
||||
services.TryAddSingleton<IEndpointFinder, DefaultEndpointFinder>();
|
||||
services.TryAddSingleton<IEndpointFinder<string>, NameBasedEndpointFinder>();
|
||||
services.TryAddSingleton<IEndpointFinder<RouteValuesBasedEndpointFinderContext>, RouteValuesBasedEndpointFinder>();
|
||||
services.TryAddSingleton<ILinkGenerator, DefaultLinkGenerator>();
|
||||
//
|
||||
// Endpoint Selection
|
||||
|
|
|
|||
|
|
@ -20,18 +20,18 @@ namespace Microsoft.AspNetCore.Routing.Internal
|
|||
new OutboundMatchClassifier());
|
||||
}
|
||||
|
||||
public IList<OutboundMatchResult> GetMatches(VirtualPathContext context)
|
||||
public IList<OutboundMatchResult> GetMatches(RouteValueDictionary values, RouteValueDictionary ambientValues)
|
||||
{
|
||||
// Perf: Avoid allocation for List if there aren't any Matches or Criteria
|
||||
if (_root.Matches.Count > 0 || _root.Criteria.Count > 0)
|
||||
{
|
||||
var results = new List<OutboundMatchResult>();
|
||||
Walk(results, context, _root, isFallbackPath: false);
|
||||
Walk(results, values, ambientValues, _root, isFallbackPath: false);
|
||||
results.Sort(OutboundMatchResultComparer.Instance);
|
||||
return results;
|
||||
}
|
||||
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
|
||||
// We need to recursively walk the decision tree based on the provided route data
|
||||
|
|
@ -61,7 +61,8 @@ namespace Microsoft.AspNetCore.Routing.Internal
|
|||
// The decision tree uses a tree data structure to execute these rules across all candidates at once.
|
||||
private void Walk(
|
||||
List<OutboundMatchResult> results,
|
||||
VirtualPathContext context,
|
||||
RouteValueDictionary values,
|
||||
RouteValueDictionary ambientValues,
|
||||
DecisionTreeNode<OutboundMatch> node,
|
||||
bool isFallbackPath)
|
||||
{
|
||||
|
|
@ -78,12 +79,12 @@ namespace Microsoft.AspNetCore.Routing.Internal
|
|||
var key = criterion.Key;
|
||||
|
||||
object value;
|
||||
if (context.Values.TryGetValue(key, out value))
|
||||
if (values.TryGetValue(key, out value))
|
||||
{
|
||||
DecisionTreeNode<OutboundMatch> branch;
|
||||
if (criterion.Branches.TryGetValue(value ?? string.Empty, out branch))
|
||||
{
|
||||
Walk(results, context, branch, isFallbackPath);
|
||||
Walk(results, values, ambientValues, branch, isFallbackPath);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -92,18 +93,18 @@ namespace Microsoft.AspNetCore.Routing.Internal
|
|||
// if an ambient value was supplied. The path explored with the empty value is considered
|
||||
// the fallback path.
|
||||
DecisionTreeNode<OutboundMatch> branch;
|
||||
if (context.AmbientValues.TryGetValue(key, out value) &&
|
||||
if (ambientValues.TryGetValue(key, out value) &&
|
||||
!criterion.Branches.Comparer.Equals(value, string.Empty))
|
||||
{
|
||||
if (criterion.Branches.TryGetValue(value, out branch))
|
||||
{
|
||||
Walk(results, context, branch, isFallbackPath);
|
||||
Walk(results, values, ambientValues, branch, isFallbackPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (criterion.Branches.TryGetValue(string.Empty, out branch))
|
||||
{
|
||||
Walk(results, context, branch, isFallbackPath: true);
|
||||
Walk(results, values, ambientValues, branch, isFallbackPath: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -155,7 +156,7 @@ namespace Microsoft.AspNetCore.Routing.Internal
|
|||
}
|
||||
|
||||
return StringComparer.Ordinal.Compare(
|
||||
x.Match.Entry.RouteTemplate.TemplateText,
|
||||
x.Match.Entry.RouteTemplate.TemplateText,
|
||||
y.Match.Entry.RouteTemplate.TemplateText);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing.Template;
|
||||
|
|
@ -19,12 +18,12 @@ namespace Microsoft.AspNetCore.Routing.Matchers
|
|||
public MatcherEndpoint(
|
||||
Func<RequestDelegate, RequestDelegate> invoker,
|
||||
string template,
|
||||
object values,
|
||||
RouteValueDictionary defaults,
|
||||
RouteValueDictionary requiredValues,
|
||||
int order,
|
||||
EndpointMetadataCollection metadata,
|
||||
string displayName,
|
||||
Address address)
|
||||
: base(metadata, displayName, address)
|
||||
string displayName)
|
||||
: base(metadata, displayName)
|
||||
{
|
||||
if (invoker == null)
|
||||
{
|
||||
|
|
@ -37,24 +36,31 @@ namespace Microsoft.AspNetCore.Routing.Matchers
|
|||
}
|
||||
|
||||
Invoker = invoker;
|
||||
Template = template;
|
||||
ParsedTemlate = TemplateParser.Parse(template);
|
||||
var mergedDefaults = GetDefaults(ParsedTemlate, new RouteValueDictionary(values));
|
||||
Values = mergedDefaults;
|
||||
Order = order;
|
||||
|
||||
Template = template;
|
||||
ParsedTemplate = TemplateParser.Parse(template);
|
||||
|
||||
RequiredValues = requiredValues;
|
||||
var mergedDefaults = GetDefaults(ParsedTemplate, defaults);
|
||||
Defaults = mergedDefaults;
|
||||
}
|
||||
|
||||
public int Order { get; }
|
||||
public Func<RequestDelegate, RequestDelegate> Invoker { get; }
|
||||
public string Template { get; }
|
||||
public IReadOnlyDictionary<string, object> Values { get; }
|
||||
public RouteValueDictionary Defaults { get; }
|
||||
|
||||
// Values required by an endpoint for it to be successfully matched on link generation
|
||||
public RouteValueDictionary RequiredValues { get; }
|
||||
|
||||
// Todo: needs review
|
||||
public RouteTemplate ParsedTemlate { get; }
|
||||
public RouteTemplate ParsedTemplate { get; }
|
||||
|
||||
private RouteValueDictionary GetDefaults(RouteTemplate parsedTemplate, RouteValueDictionary defaults)
|
||||
// Merge inline and non inline defaults into one
|
||||
private RouteValueDictionary GetDefaults(RouteTemplate parsedTemplate, RouteValueDictionary nonInlineDefaults)
|
||||
{
|
||||
var result = defaults == null ? new RouteValueDictionary() : new RouteValueDictionary(defaults);
|
||||
var result = nonInlineDefaults == null ? new RouteValueDictionary() : new RouteValueDictionary(nonInlineDefaults);
|
||||
|
||||
foreach (var parameter in parsedTemplate.Parameters)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
|
|||
{
|
||||
if (feature.Endpoint is MatcherEndpoint endpoint)
|
||||
{
|
||||
foreach (var kvp in endpoint.Values)
|
||||
foreach (var kvp in endpoint.Defaults)
|
||||
{
|
||||
if (!feature.Values.ContainsKey(kvp.Key))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Routing.Matchers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing
|
||||
{
|
||||
internal class NameBasedEndpointFinder : IEndpointFinder<string>
|
||||
{
|
||||
private readonly CompositeEndpointDataSource _endpointDatasource;
|
||||
private readonly ILogger<NameBasedEndpointFinder> _logger;
|
||||
|
||||
public NameBasedEndpointFinder(
|
||||
CompositeEndpointDataSource endpointDataSource,
|
||||
ILogger<NameBasedEndpointFinder> logger)
|
||||
{
|
||||
_endpointDatasource = endpointDataSource;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public IEnumerable<Endpoint> FindEndpoints(string endpointName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(endpointName))
|
||||
{
|
||||
return Array.Empty<Endpoint>();
|
||||
}
|
||||
|
||||
var endpoints = _endpointDatasource.Endpoints.OfType<MatcherEndpoint>();
|
||||
|
||||
foreach (var endpoint in endpoints)
|
||||
{
|
||||
var nameMetadata = endpoint.Metadata.GetMetadata<INameMetadata>();
|
||||
if (nameMetadata != null &&
|
||||
string.Equals(endpointName, nameMetadata.Name, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return new[] { endpoint };
|
||||
}
|
||||
}
|
||||
return Array.Empty<Endpoint>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Routing.EndpointFinders;
|
||||
using Microsoft.AspNetCore.Routing.Internal;
|
||||
using Microsoft.AspNetCore.Routing.Matchers;
|
||||
using Microsoft.AspNetCore.Routing.Template;
|
||||
using Microsoft.AspNetCore.Routing.Tree;
|
||||
using Microsoft.Extensions.ObjectPool;
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing
|
||||
{
|
||||
internal class RouteValuesBasedEndpointFinder : IEndpointFinder<RouteValuesBasedEndpointFinderContext>
|
||||
{
|
||||
private readonly CompositeEndpointDataSource _endpointDataSource;
|
||||
private readonly IInlineConstraintResolver _inlineConstraintResolver;
|
||||
private readonly ObjectPool<UriBuildingContext> _objectPool;
|
||||
private LinkGenerationDecisionTree _allMatchesLinkGenerationTree;
|
||||
private IDictionary<string, LinkGenerationDecisionTree> _namedMatches;
|
||||
|
||||
public RouteValuesBasedEndpointFinder(
|
||||
CompositeEndpointDataSource endpointDataSource,
|
||||
ObjectPool<UriBuildingContext> objectPool,
|
||||
IInlineConstraintResolver inlineConstraintResolver)
|
||||
{
|
||||
_endpointDataSource = endpointDataSource;
|
||||
_objectPool = objectPool;
|
||||
_inlineConstraintResolver = inlineConstraintResolver;
|
||||
|
||||
BuildOutboundMatches();
|
||||
}
|
||||
|
||||
public IEnumerable<Endpoint> FindEndpoints(RouteValuesBasedEndpointFinderContext context)
|
||||
{
|
||||
IEnumerable<OutboundMatchResult> matchResults = null;
|
||||
if (string.IsNullOrEmpty(context.RouteName))
|
||||
{
|
||||
matchResults = _allMatchesLinkGenerationTree.GetMatches(
|
||||
context.ExplicitValues,
|
||||
context.AmbientValues);
|
||||
}
|
||||
else if (_namedMatches.TryGetValue(context.RouteName, out var linkGenerationTree))
|
||||
{
|
||||
matchResults = linkGenerationTree.GetMatches(
|
||||
context.ExplicitValues,
|
||||
context.AmbientValues);
|
||||
}
|
||||
|
||||
if (matchResults == null || !matchResults.Any())
|
||||
{
|
||||
return Array.Empty<Endpoint>();
|
||||
}
|
||||
|
||||
return matchResults
|
||||
.Select(matchResult => matchResult.Match)
|
||||
.Select(match => (MatcherEndpoint)match.Entry.Data);
|
||||
}
|
||||
|
||||
private void BuildOutboundMatches()
|
||||
{
|
||||
var (allOutboundMatches, namedOutboundMatches) = GetOutboundMatches();
|
||||
_namedMatches = GetNamedMatches(namedOutboundMatches);
|
||||
_allMatchesLinkGenerationTree = new LinkGenerationDecisionTree(allOutboundMatches.ToArray());
|
||||
}
|
||||
|
||||
private (IEnumerable<OutboundMatch>, IDictionary<string, List<OutboundMatch>>) GetOutboundMatches()
|
||||
{
|
||||
var allOutboundMatches = new List<OutboundMatch>();
|
||||
var namedOutboundMatches = new Dictionary<string, List<OutboundMatch>>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
var endpoints = _endpointDataSource.Endpoints.OfType<MatcherEndpoint>();
|
||||
foreach (var endpoint in endpoints)
|
||||
{
|
||||
var entry = CreateOutboundRouteEntry(endpoint);
|
||||
|
||||
var outboundMatch = new OutboundMatch() { Entry = entry };
|
||||
allOutboundMatches.Add(outboundMatch);
|
||||
|
||||
if (string.IsNullOrEmpty(entry.RouteName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
List<OutboundMatch> matches;
|
||||
if (!namedOutboundMatches.TryGetValue(entry.RouteName, out matches))
|
||||
{
|
||||
matches = new List<OutboundMatch>();
|
||||
namedOutboundMatches.Add(entry.RouteName, matches);
|
||||
}
|
||||
matches.Add(outboundMatch);
|
||||
}
|
||||
|
||||
return (allOutboundMatches, namedOutboundMatches);
|
||||
}
|
||||
|
||||
private OutboundRouteEntry CreateOutboundRouteEntry(MatcherEndpoint endpoint)
|
||||
{
|
||||
var routeNameMetadata = endpoint.Metadata.GetMetadata<IRouteNameMetadata>();
|
||||
var entry = new OutboundRouteEntry()
|
||||
{
|
||||
Handler = NullRouter.Instance,
|
||||
Order = endpoint.Order,
|
||||
Precedence = RoutePrecedence.ComputeOutbound(endpoint.ParsedTemplate),
|
||||
RequiredLinkValues = endpoint.RequiredValues,
|
||||
RouteTemplate = endpoint.ParsedTemplate,
|
||||
Data = endpoint,
|
||||
RouteName = routeNameMetadata?.Name,
|
||||
};
|
||||
|
||||
// TODO: review. These route constriants should be constructed when the endpoint
|
||||
// is built. This way they can be checked for validity on app startup too
|
||||
var constraintBuilder = new RouteConstraintBuilder(
|
||||
_inlineConstraintResolver,
|
||||
endpoint.ParsedTemplate.TemplateText);
|
||||
foreach (var parameter in endpoint.ParsedTemplate.Parameters)
|
||||
{
|
||||
if (parameter.InlineConstraints != null)
|
||||
{
|
||||
if (parameter.IsOptional)
|
||||
{
|
||||
constraintBuilder.SetOptional(parameter.Name);
|
||||
}
|
||||
|
||||
foreach (var constraint in parameter.InlineConstraints)
|
||||
{
|
||||
constraintBuilder.AddResolvedConstraint(parameter.Name, constraint.Constraint);
|
||||
}
|
||||
}
|
||||
}
|
||||
entry.Constraints = constraintBuilder.Build();
|
||||
entry.Defaults = endpoint.Defaults;
|
||||
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;
|
||||
}
|
||||
|
||||
// Used only to hook up link generation, and it doesn't need to do anything.
|
||||
private class NullRouter : IRouter
|
||||
{
|
||||
public static readonly NullRouter Instance = new NullRouter();
|
||||
|
||||
public VirtualPathData GetVirtualPath(VirtualPathContext context)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public Task RouteAsync(RouteContext context)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +1,14 @@
|
|||
// 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
|
||||
namespace Microsoft.AspNetCore.Routing.EndpointFinders
|
||||
{
|
||||
public class LinkGeneratorContext
|
||||
public class RouteValuesBasedEndpointFinderContext
|
||||
{
|
||||
public Address Address { get; set; }
|
||||
public string RouteName { get; set; }
|
||||
|
||||
public RouteValueDictionary ExplicitValues { get; set; }
|
||||
|
||||
public RouteValueDictionary AmbientValues { get; set; }
|
||||
|
||||
public RouteValueDictionary SuppliedValues { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -58,5 +58,10 @@ namespace Microsoft.AspNetCore.Routing.Tree
|
|||
/// Gets or sets the <see cref="RouteTemplate"/>.
|
||||
/// </summary>
|
||||
public RouteTemplate RouteTemplate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the data that is associated with this entry.
|
||||
/// </summary>
|
||||
public object Data { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -150,7 +150,7 @@ namespace Microsoft.AspNetCore.Routing.Tree
|
|||
|
||||
// The decision tree will give us back all entries that match the provided route data in the correct
|
||||
// order. We just need to iterate them and use the first one that can generate a link.
|
||||
var matches = _linkGenerationTree.GetMatches(context);
|
||||
var matches = _linkGenerationTree.GetMatches(context.Values, context.AmbientValues);
|
||||
|
||||
if (matches == null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,161 +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.Routing.TestObjects;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing
|
||||
{
|
||||
public class DefaultEndpointFinderTest
|
||||
{
|
||||
[Fact]
|
||||
public void FindEndpoints_IgnoresCase_ForRouteNameLookup()
|
||||
{
|
||||
// Arrange
|
||||
var endpoint1 = CreateEndpoint(new Address("home"));
|
||||
var endpoint2 = CreateEndpoint(new Address("admin"));
|
||||
var endpointFinder = CreateDefaultEndpointFinder(endpoint1, endpoint2);
|
||||
|
||||
// Act
|
||||
var result = endpointFinder.FindEndpoints(new Address("Admin"));
|
||||
|
||||
// Assert
|
||||
var endpoint = Assert.Single(result);
|
||||
Assert.Same(endpoint2, endpoint);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindEndpoints_MultipleEndpointsWithSameName_ReturnsFirstEndpoint_WithMatchingName()
|
||||
{
|
||||
// Arrange
|
||||
var name = "common-tag-for-all-my-section's-routes";
|
||||
var endpoint1 = CreateEndpoint(new Address(name));
|
||||
var endpoint2 = CreateEndpoint(new Address("admin"));
|
||||
var endpoint3 = CreateEndpoint(new Address(name));
|
||||
var endpoint4 = CreateEndpoint(new Address("products"));
|
||||
var endpointFinder = CreateDefaultEndpointFinder(endpoint1, endpoint2, endpoint3, endpoint4);
|
||||
|
||||
// Act
|
||||
var result = endpointFinder.FindEndpoints(new Address(name));
|
||||
|
||||
// Assert
|
||||
var endpoint = Assert.Single(result);
|
||||
Assert.Same(endpoint, endpoint1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindEndpoints_ReturnsAllEndpoints_WhenNoEndpointsHaveAddress()
|
||||
{
|
||||
// Arrange
|
||||
var endpoint1 = CreateEndpoint(address: null);
|
||||
var endpoint2 = CreateEndpoint(address: null);
|
||||
var endpointFinder = CreateDefaultEndpointFinder(endpoint1, endpoint2);
|
||||
|
||||
// Act
|
||||
var result = endpointFinder.FindEndpoints(new Address("Admin"));
|
||||
|
||||
// Assert
|
||||
Assert.Collection(
|
||||
result,
|
||||
(ep) => Assert.Same(endpoint1, ep),
|
||||
(ep) => Assert.Same(endpoint2, ep));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindEndpoints_ReturnsAllEndpoints_WhenLookupAddress_IsNull()
|
||||
{
|
||||
// Arrange
|
||||
var endpoint1 = CreateEndpoint(new Address("home"));
|
||||
var endpoint2 = CreateEndpoint(new Address("admin"));
|
||||
var endpointFinder = CreateDefaultEndpointFinder(endpoint1, endpoint2);
|
||||
|
||||
// Act
|
||||
var result = endpointFinder.FindEndpoints(lookupAddress: null);
|
||||
|
||||
// Assert
|
||||
Assert.Collection(
|
||||
result,
|
||||
(ep) => Assert.Same(endpoint1, ep),
|
||||
(ep) => Assert.Same(endpoint2, ep));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindEndpoints_ReturnsAllEndpoints_WhenNoEndpointsHaveAddress_AndLookupAddress_IsNull()
|
||||
{
|
||||
// Arrange
|
||||
var endpoint1 = CreateEndpoint(address: null);
|
||||
var endpoint2 = CreateEndpoint(address: null);
|
||||
var endpointFinder = CreateDefaultEndpointFinder(endpoint1, endpoint2);
|
||||
|
||||
// Act
|
||||
var result = endpointFinder.FindEndpoints(lookupAddress: null);
|
||||
|
||||
// Assert
|
||||
Assert.Collection(
|
||||
result,
|
||||
(ep) => Assert.Same(endpoint1, ep),
|
||||
(ep) => Assert.Same(endpoint2, ep));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindEndpoints_ReturnsAllEndpoints_WhenNoInformationGiven_OnLookupAddress()
|
||||
{
|
||||
// Arrange
|
||||
var endpoint1 = CreateEndpoint(new Address("home"));
|
||||
var endpoint2 = CreateEndpoint(new Address("admin"));
|
||||
var endpointFinder = CreateDefaultEndpointFinder(endpoint1, endpoint2);
|
||||
|
||||
// Act
|
||||
var result = endpointFinder.FindEndpoints(new Address(name: null));
|
||||
|
||||
// Assert
|
||||
Assert.Collection(
|
||||
result,
|
||||
(ep) => Assert.Same(endpoint1, ep),
|
||||
(ep) => Assert.Same(endpoint2, ep));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindEndpoints_ReturnsEmpty_WhenNoEndpointFound_WithLookupAddress_Name()
|
||||
{
|
||||
// Arrange
|
||||
var endpoint1 = CreateEndpoint(new Address("home"));
|
||||
var endpoint2 = CreateEndpoint(new Address("admin"));
|
||||
var endpointFinder = CreateDefaultEndpointFinder(endpoint1, endpoint2);
|
||||
|
||||
// Act
|
||||
var result = endpointFinder.FindEndpoints(new Address("DoesNotExist"));
|
||||
|
||||
// Assert
|
||||
Assert.Empty(result);
|
||||
}
|
||||
|
||||
private Endpoint CreateEndpoint(Address address)
|
||||
{
|
||||
return new TestEndpoint(
|
||||
EndpointMetadataCollection.Empty,
|
||||
displayName: null,
|
||||
address: address);
|
||||
}
|
||||
|
||||
private DefaultEndpointFinder CreateDefaultEndpointFinder(params Endpoint[] endpoints)
|
||||
{
|
||||
return new DefaultEndpointFinder(
|
||||
new CompositeEndpointDataSource(new[] { new DefaultEndpointDataSource(endpoints) }),
|
||||
NullLogger<DefaultEndpointFinder>.Instance);
|
||||
}
|
||||
|
||||
private class HomeController
|
||||
{
|
||||
public void Index() { }
|
||||
public void Contact() { }
|
||||
}
|
||||
|
||||
private class AdminController
|
||||
{
|
||||
public void Index() { }
|
||||
public void Contact() { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,10 +4,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Routing.EndpointFinders;
|
||||
using Microsoft.AspNetCore.Routing.Internal;
|
||||
using Microsoft.AspNetCore.Routing.Matchers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.ObjectPool;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
|
@ -21,11 +21,11 @@ namespace Microsoft.AspNetCore.Routing
|
|||
{
|
||||
// Arrange
|
||||
var endpoint = CreateEndpoint("{controller}");
|
||||
var linkGenerator = CreateLinkGenerator(CreateEndpointFinder(endpoint));
|
||||
var context = CreateLinkGeneratorContext(new { controller = "Home" });
|
||||
var linkGenerator = CreateLinkGenerator();
|
||||
var context = CreateRouteValuesContext(new { controller = "Home" });
|
||||
|
||||
// Act
|
||||
var link = linkGenerator.GetLink(context);
|
||||
var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("/Home", link);
|
||||
|
|
@ -37,11 +37,12 @@ namespace Microsoft.AspNetCore.Routing
|
|||
// Arrange
|
||||
var expectedMessage = "Could not find a matching endpoint to generate a link.";
|
||||
var endpoint = CreateEndpoint("{controller}/{action}");
|
||||
var linkGenerator = CreateLinkGenerator(CreateEndpointFinder(endpoint));
|
||||
var context = CreateLinkGeneratorContext(new { controller = "Home" });
|
||||
var linkGenerator = CreateLinkGenerator();
|
||||
var context = CreateRouteValuesContext(new { controller = "Home" });
|
||||
|
||||
// Act & Assert
|
||||
var exception = Assert.Throws<InvalidOperationException>(() => linkGenerator.GetLink(context));
|
||||
var exception = Assert.Throws<InvalidOperationException>(
|
||||
() => linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues));
|
||||
Assert.Equal(expectedMessage, exception.Message);
|
||||
}
|
||||
|
||||
|
|
@ -50,11 +51,15 @@ namespace Microsoft.AspNetCore.Routing
|
|||
{
|
||||
// Arrange
|
||||
var endpoint = CreateEndpoint("{controller}/{action}");
|
||||
var linkGenerator = CreateLinkGenerator(CreateEndpointFinder(endpoint));
|
||||
var context = CreateLinkGeneratorContext(new { controller = "Home" });
|
||||
var linkGenerator = CreateLinkGenerator();
|
||||
var context = CreateRouteValuesContext(new { controller = "Home" });
|
||||
|
||||
// Act
|
||||
var canGenerateLink = linkGenerator.TryGetLink(context, out var link);
|
||||
var canGenerateLink = linkGenerator.TryGetLink(
|
||||
new[] { endpoint },
|
||||
context.ExplicitValues,
|
||||
context.AmbientValues,
|
||||
out var link);
|
||||
|
||||
// Assert
|
||||
Assert.False(canGenerateLink);
|
||||
|
|
@ -68,11 +73,14 @@ namespace Microsoft.AspNetCore.Routing
|
|||
var endpoint1 = CreateEndpoint("{controller}/{action}/{id?}");
|
||||
var endpoint2 = CreateEndpoint("{controller}/{action}");
|
||||
var endpoint3 = CreateEndpoint("{controller}");
|
||||
var linkGenerator = CreateLinkGenerator(CreateEndpointFinder(endpoint1, endpoint2, endpoint3));
|
||||
var context = CreateLinkGeneratorContext(new { controller = "Home", action = "Index", id = "10" });
|
||||
var linkGenerator = CreateLinkGenerator();
|
||||
var context = CreateRouteValuesContext(new { controller = "Home", action = "Index", id = "10" });
|
||||
|
||||
// Act
|
||||
var link = linkGenerator.GetLink(context);
|
||||
var link = linkGenerator.GetLink(
|
||||
new[] { endpoint1, endpoint2, endpoint3 },
|
||||
context.ExplicitValues,
|
||||
context.AmbientValues);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("/Home/Index/10", link);
|
||||
|
|
@ -85,11 +93,14 @@ namespace Microsoft.AspNetCore.Routing
|
|||
var endpoint1 = CreateEndpoint("{controller}/{action}/{id}");
|
||||
var endpoint2 = CreateEndpoint("{controller}/{action}");
|
||||
var endpoint3 = CreateEndpoint("{controller}");
|
||||
var linkGenerator = CreateLinkGenerator(CreateEndpointFinder(endpoint1, endpoint2, endpoint3));
|
||||
var context = CreateLinkGeneratorContext(new { controller = "Home", action = "Index" });
|
||||
var linkGenerator = CreateLinkGenerator();
|
||||
var context = CreateRouteValuesContext(new { controller = "Home", action = "Index" });
|
||||
|
||||
// Act
|
||||
var link = linkGenerator.GetLink(context);
|
||||
var link = linkGenerator.GetLink(
|
||||
new[] { endpoint1, endpoint2, endpoint3 },
|
||||
context.ExplicitValues,
|
||||
context.AmbientValues);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("/Home/Index", link);
|
||||
|
|
@ -100,13 +111,13 @@ namespace Microsoft.AspNetCore.Routing
|
|||
{
|
||||
// Arrange
|
||||
var endpoint = CreateEndpoint("{controller}/{action}");
|
||||
var linkGenerator = CreateLinkGenerator(CreateEndpointFinder(endpoint));
|
||||
var context = CreateLinkGeneratorContext(
|
||||
var linkGenerator = CreateLinkGenerator();
|
||||
var context = CreateRouteValuesContext(
|
||||
suppliedValues: new { name = "name with %special #characters" },
|
||||
ambientValues: new { controller = "Home", action = "Index" });
|
||||
|
||||
// Act
|
||||
var link = linkGenerator.GetLink(context);
|
||||
var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("/Home/Index?name=name%20with%20%25special%20%23characters", link);
|
||||
|
|
@ -117,13 +128,13 @@ namespace Microsoft.AspNetCore.Routing
|
|||
{
|
||||
// Arrange
|
||||
var endpoint = CreateEndpoint("{controller}/{action}");
|
||||
var linkGenerator = CreateLinkGenerator(CreateEndpointFinder(endpoint));
|
||||
var context = CreateLinkGeneratorContext(
|
||||
var linkGenerator = CreateLinkGenerator();
|
||||
var context = CreateRouteValuesContext(
|
||||
new { color = new List<string> { "red", "green", "blue" } },
|
||||
new { controller = "Home", action = "Index" });
|
||||
|
||||
// Act
|
||||
var link = linkGenerator.GetLink(context);
|
||||
var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("/Home/Index?color=red&color=green&color=blue", link);
|
||||
|
|
@ -134,13 +145,13 @@ namespace Microsoft.AspNetCore.Routing
|
|||
{
|
||||
// Arrange
|
||||
var endpoint = CreateEndpoint("{controller}/{action}");
|
||||
var linkGenerator = CreateLinkGenerator(CreateEndpointFinder(endpoint));
|
||||
var context = CreateLinkGeneratorContext(
|
||||
var linkGenerator = CreateLinkGenerator();
|
||||
var context = CreateRouteValuesContext(
|
||||
new { items = new List<int> { 10, 20, 30 } },
|
||||
new { controller = "Home", action = "Index" });
|
||||
|
||||
// Act
|
||||
var link = linkGenerator.GetLink(context);
|
||||
var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("/Home/Index?items=10&items=20&items=30", link);
|
||||
|
|
@ -151,13 +162,13 @@ namespace Microsoft.AspNetCore.Routing
|
|||
{
|
||||
// Arrange
|
||||
var endpoint = CreateEndpoint("{controller}/{action}");
|
||||
var linkGenerator = CreateLinkGenerator(CreateEndpointFinder(endpoint));
|
||||
var context = CreateLinkGeneratorContext(
|
||||
var linkGenerator = CreateLinkGenerator();
|
||||
var context = CreateRouteValuesContext(
|
||||
new { color = new List<string> { } },
|
||||
new { controller = "Home", action = "Index" });
|
||||
|
||||
// Act
|
||||
var link = linkGenerator.GetLink(context);
|
||||
var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("/Home/Index", link);
|
||||
|
|
@ -168,13 +179,13 @@ namespace Microsoft.AspNetCore.Routing
|
|||
{
|
||||
// Arrange
|
||||
var endpoint = CreateEndpoint("{controller}/{action}");
|
||||
var linkGenerator = CreateLinkGenerator(CreateEndpointFinder(endpoint));
|
||||
var context = CreateLinkGeneratorContext(
|
||||
var linkGenerator = CreateLinkGenerator();
|
||||
var context = CreateRouteValuesContext(
|
||||
new { page = 1, color = new List<string> { "red", "green", "blue" }, message = "textfortest" },
|
||||
new { controller = "Home", action = "Index" });
|
||||
|
||||
// Act
|
||||
var link = linkGenerator.GetLink(context);
|
||||
var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("/Home/Index?page=1&color=red&color=green&color=blue&message=textfortest", link);
|
||||
|
|
@ -185,13 +196,13 @@ namespace Microsoft.AspNetCore.Routing
|
|||
{
|
||||
// Arrange
|
||||
var endpoint = CreateEndpoint("{controller}/{action}");
|
||||
var linkGenerator = CreateLinkGenerator(CreateEndpointFinder(endpoint));
|
||||
var context = CreateLinkGeneratorContext(
|
||||
var linkGenerator = CreateLinkGenerator();
|
||||
var context = CreateRouteValuesContext(
|
||||
suppliedValues: new { action = "Index" },
|
||||
ambientValues: new { controller = "Home" });
|
||||
|
||||
// Act
|
||||
var link = linkGenerator.GetLink(context);
|
||||
var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("/Home/Index", link);
|
||||
|
|
@ -201,9 +212,9 @@ namespace Microsoft.AspNetCore.Routing
|
|||
//public void RouteGenerationRejectsConstraints()
|
||||
//{
|
||||
// // Arrange
|
||||
// var context = CreateLinkGeneratorContext(new { p1 = "abcd" });
|
||||
// var context = CreateRouteValuesContext(new { p1 = "abcd" });
|
||||
|
||||
// var endpoint = CreateEndpoint(
|
||||
// var endpoint = CreateEndpoints(
|
||||
// "{p1}/{p2}",
|
||||
// new { p2 = "catchall" },
|
||||
// true,
|
||||
|
|
@ -220,16 +231,16 @@ namespace Microsoft.AspNetCore.Routing
|
|||
//public void RouteGenerationAcceptsConstraints()
|
||||
//{
|
||||
// // Arrange
|
||||
// var context = CreateLinkGeneratorContext(new { p1 = "hello", p2 = "1234" });
|
||||
// var context = CreateRouteValuesContext(new { p1 = "hello", p2 = "1234" });
|
||||
|
||||
// var endpoint = CreateEndpoint(
|
||||
// var endpoint = CreateEndpoints(
|
||||
// "{p1}/{p2}",
|
||||
// new { p2 = "catchall" },
|
||||
// true,
|
||||
// new RouteValueDictionary(new { p2 = "\\d{4}" }));
|
||||
|
||||
// // Act
|
||||
// var link = linkGenerator.GetLink(context);
|
||||
// var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// // Assert
|
||||
// Assert.NotNull(pathData);
|
||||
|
|
@ -242,9 +253,9 @@ namespace Microsoft.AspNetCore.Routing
|
|||
//public void RouteWithCatchAllRejectsConstraints()
|
||||
//{
|
||||
// // Arrange
|
||||
// var context = CreateLinkGeneratorContext(new { p1 = "abcd" });
|
||||
// var context = CreateRouteValuesContext(new { p1 = "abcd" });
|
||||
|
||||
// var endpoint = CreateEndpoint(
|
||||
// var endpoint = CreateEndpoints(
|
||||
// "{p1}/{*p2}",
|
||||
// new { p2 = "catchall" },
|
||||
// true,
|
||||
|
|
@ -261,16 +272,16 @@ namespace Microsoft.AspNetCore.Routing
|
|||
//public void RouteWithCatchAllAcceptsConstraints()
|
||||
//{
|
||||
// // Arrange
|
||||
// var context = CreateLinkGeneratorContext(new { p1 = "hello", p2 = "1234" });
|
||||
// var context = CreateRouteValuesContext(new { p1 = "hello", p2 = "1234" });
|
||||
|
||||
// var endpoint = CreateEndpoint(
|
||||
// var endpoint = CreateEndpoints(
|
||||
// "{p1}/{*p2}",
|
||||
// new { p2 = "catchall" },
|
||||
// true,
|
||||
// new RouteValueDictionary(new { p2 = "\\d{4}" }));
|
||||
|
||||
// // Act
|
||||
// var link = linkGenerator.GetLink(context);
|
||||
// var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// // Assert
|
||||
// Assert.NotNull(pathData);
|
||||
|
|
@ -283,7 +294,7 @@ namespace Microsoft.AspNetCore.Routing
|
|||
//public void GetLinkWithNonParameterConstraintReturnsUrlWithoutQueryString()
|
||||
//{
|
||||
// // Arrange
|
||||
// var context = CreateLinkGeneratorContext(new { p1 = "hello", p2 = "1234" });
|
||||
// var context = CreateRouteValuesContext(new { p1 = "hello", p2 = "1234" });
|
||||
|
||||
// var target = new Mock<IRouteConstraint>();
|
||||
// target
|
||||
|
|
@ -297,14 +308,14 @@ namespace Microsoft.AspNetCore.Routing
|
|||
// .Returns(true)
|
||||
// .Verifiable();
|
||||
|
||||
// var endpoint = CreateEndpoint(
|
||||
// var endpoint = CreateEndpoints(
|
||||
// "{p1}/{p2}",
|
||||
// new { p2 = "catchall" },
|
||||
// true,
|
||||
// new RouteValueDictionary(new { p2 = target.Object }));
|
||||
|
||||
// // Act
|
||||
// var link = linkGenerator.GetLink(context);
|
||||
// var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// // Assert
|
||||
// Assert.NotNull(pathData);
|
||||
|
|
@ -322,13 +333,13 @@ namespace Microsoft.AspNetCore.Routing
|
|||
//{
|
||||
// // Arrange
|
||||
// var constraint = new CapturingConstraint();
|
||||
// var endpoint = CreateEndpoint(
|
||||
// var endpoint = CreateEndpoints(
|
||||
// template: "slug/{controller}/{action}",
|
||||
// defaultValues: null,
|
||||
// handleRequest: true,
|
||||
// constraints: new { c = constraint });
|
||||
|
||||
// var context = CreateLinkGeneratorContext(
|
||||
// var context = CreateRouteValuesContext(
|
||||
// values: new { action = "Store" },
|
||||
// ambientValues: new { Controller = "Home", action = "Blog", extra = "42" });
|
||||
|
||||
|
|
@ -336,7 +347,7 @@ namespace Microsoft.AspNetCore.Routing
|
|||
// new { controller = "Home", action = "Store", extra = "42" });
|
||||
|
||||
// // Act
|
||||
// var link = linkGenerator.GetLink(context);
|
||||
// var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// // Assert
|
||||
// Assert.Equal("/slug/Home/Store", link);
|
||||
|
|
@ -353,13 +364,13 @@ namespace Microsoft.AspNetCore.Routing
|
|||
//{
|
||||
// // Arrange
|
||||
// var constraint = new CapturingConstraint();
|
||||
// var endpoint = CreateEndpoint(
|
||||
// var endpoint = CreateEndpoints(
|
||||
// template: "slug/{controller}/{action}",
|
||||
// defaultValues: new { otherthing = "17" },
|
||||
// handleRequest: true,
|
||||
// constraints: new { c = constraint });
|
||||
|
||||
// var context = CreateLinkGeneratorContext(
|
||||
// var context = CreateRouteValuesContext(
|
||||
// values: new { action = "Store" },
|
||||
// ambientValues: new { Controller = "Home", action = "Blog" });
|
||||
|
||||
|
|
@ -367,7 +378,7 @@ namespace Microsoft.AspNetCore.Routing
|
|||
// new { controller = "Home", action = "Store" });
|
||||
|
||||
// // Act
|
||||
// var link = linkGenerator.GetLink(context);
|
||||
// var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// // Assert
|
||||
// Assert.Equal("/slug/Home/Store", link);
|
||||
|
|
@ -383,13 +394,13 @@ namespace Microsoft.AspNetCore.Routing
|
|||
//{
|
||||
// // Arrange
|
||||
// var constraint = new CapturingConstraint();
|
||||
// var endpoint = CreateEndpoint(
|
||||
// var endpoint = CreateEndpoints(
|
||||
// template: "slug/{controller}/{action}",
|
||||
// defaultValues: new { action = "Index" },
|
||||
// handleRequest: true,
|
||||
// constraints: new { c = constraint });
|
||||
|
||||
// var context = CreateLinkGeneratorContext(
|
||||
// var context = CreateRouteValuesContext(
|
||||
// values: new { controller = "Shopping" },
|
||||
// ambientValues: new { Controller = "Home", action = "Blog" });
|
||||
|
||||
|
|
@ -397,7 +408,7 @@ namespace Microsoft.AspNetCore.Routing
|
|||
// new { controller = "Shopping", action = "Index" });
|
||||
|
||||
// // Act
|
||||
// var link = linkGenerator.GetLink(context);
|
||||
// var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// // Assert
|
||||
// Assert.Equal("/slug/Shopping", link);
|
||||
|
|
@ -414,13 +425,13 @@ namespace Microsoft.AspNetCore.Routing
|
|||
//{
|
||||
// // Arrange
|
||||
// var constraint = new CapturingConstraint();
|
||||
// var endpoint = CreateEndpoint(
|
||||
// var endpoint = CreateEndpoints(
|
||||
// template: "slug/{controller}/{action}",
|
||||
// defaultValues: new { otherthing = "17", thirdthing = "13" },
|
||||
// handleRequest: true,
|
||||
// constraints: new { c = constraint });
|
||||
|
||||
// var context = CreateLinkGeneratorContext(
|
||||
// var context = CreateRouteValuesContext(
|
||||
// values: new { action = "Store", thirdthing = "13" },
|
||||
// ambientValues: new { Controller = "Home", action = "Blog", otherthing = "17" });
|
||||
|
||||
|
|
@ -428,7 +439,7 @@ namespace Microsoft.AspNetCore.Routing
|
|||
// new { controller = "Home", action = "Store", otherthing = "17", thirdthing = "13" });
|
||||
|
||||
// // Act
|
||||
// var link = linkGenerator.GetLink(context);
|
||||
// var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// // Assert
|
||||
// Assert.Equal("/slug/Home/Store", link);
|
||||
|
|
@ -442,12 +453,12 @@ namespace Microsoft.AspNetCore.Routing
|
|||
//public void GetLink_InlineConstraints_Success()
|
||||
//{
|
||||
// // Arrange
|
||||
// var endpoint = CreateEndpoint("{controller}/{action}/{id:int}");
|
||||
// var context = CreateLinkGeneratorContext(
|
||||
// var endpoint = CreateEndpoints("{controller}/{action}/{id:int}");
|
||||
// var context = CreateRouteValuesContext(
|
||||
// values: new { action = "Index", controller = "Home", id = 4 });
|
||||
|
||||
// // Act
|
||||
// var link = linkGenerator.GetLink(context);
|
||||
// var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// // Assert
|
||||
// Assert.Equal("/Home/Index/4", link);
|
||||
|
|
@ -459,8 +470,8 @@ namespace Microsoft.AspNetCore.Routing
|
|||
//public void GetLink_InlineConstraints_NonMatchingvalue()
|
||||
//{
|
||||
// // Arrange
|
||||
// var endpoint = CreateEndpoint("{controller}/{action}/{id:int}");
|
||||
// var context = CreateLinkGeneratorContext(
|
||||
// var endpoint = CreateEndpoints("{controller}/{action}/{id:int}");
|
||||
// var context = CreateRouteValuesContext(
|
||||
// values: new { action = "Index", controller = "Home", id = "asf" });
|
||||
|
||||
// // Act
|
||||
|
|
@ -474,12 +485,12 @@ namespace Microsoft.AspNetCore.Routing
|
|||
//public void GetLink_InlineConstraints_OptionalParameter_ValuePresent()
|
||||
//{
|
||||
// // Arrange
|
||||
// var endpoint = CreateEndpoint("{controller}/{action}/{id:int?}");
|
||||
// var context = CreateLinkGeneratorContext(
|
||||
// var endpoint = CreateEndpoints("{controller}/{action}/{id:int?}");
|
||||
// var context = CreateRouteValuesContext(
|
||||
// values: new { action = "Index", controller = "Home", id = 98 });
|
||||
|
||||
// // Act
|
||||
// var link = linkGenerator.GetLink(context);
|
||||
// var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// // Assert
|
||||
// Assert.Equal("/Home/Index/98", link);
|
||||
|
|
@ -491,12 +502,12 @@ namespace Microsoft.AspNetCore.Routing
|
|||
//public void GetLink_InlineConstraints_OptionalParameter_ValueNotPresent()
|
||||
//{
|
||||
// // Arrange
|
||||
// var endpoint = CreateEndpoint("{controller}/{action}/{id:int?}");
|
||||
// var context = CreateLinkGeneratorContext(
|
||||
// var endpoint = CreateEndpoints("{controller}/{action}/{id:int?}");
|
||||
// var context = CreateRouteValuesContext(
|
||||
// values: new { action = "Index", controller = "Home" });
|
||||
|
||||
// // Act
|
||||
// var link = linkGenerator.GetLink(context);
|
||||
// var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// // Assert
|
||||
// Assert.Equal("/Home/Index", link);
|
||||
|
|
@ -508,8 +519,8 @@ namespace Microsoft.AspNetCore.Routing
|
|||
//public void GetLink_InlineConstraints_OptionalParameter_ValuePresent_ConstraintFails()
|
||||
//{
|
||||
// // Arrange
|
||||
// var endpoint = CreateEndpoint("{controller}/{action}/{id:int?}");
|
||||
// var context = CreateLinkGeneratorContext(
|
||||
// var endpoint = CreateEndpoints("{controller}/{action}/{id:int?}");
|
||||
// var context = CreateRouteValuesContext(
|
||||
// values: new { action = "Index", controller = "Home", id = "sdfd" });
|
||||
|
||||
// // Act
|
||||
|
|
@ -523,12 +534,12 @@ namespace Microsoft.AspNetCore.Routing
|
|||
//public void GetLink_InlineConstraints_CompositeInlineConstraint()
|
||||
//{
|
||||
// // Arrange
|
||||
// var endpoint = CreateEndpoint("{controller}/{action}/{id:int:range(1,20)}");
|
||||
// var context = CreateLinkGeneratorContext(
|
||||
// var endpoint = CreateEndpoints("{controller}/{action}/{id:int:range(1,20)}");
|
||||
// var context = CreateRouteValuesContext(
|
||||
// values: new { action = "Index", controller = "Home", id = 14 });
|
||||
|
||||
// // Act
|
||||
// var link = linkGenerator.GetLink(context);
|
||||
// var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// // Assert
|
||||
// Assert.Equal("/Home/Index/14", link);
|
||||
|
|
@ -541,17 +552,17 @@ namespace Microsoft.AspNetCore.Routing
|
|||
//{
|
||||
// // Arrange
|
||||
// var constraint = new MaxLengthRouteConstraint(20);
|
||||
// var endpoint = CreateEndpoint(
|
||||
// var endpoint = CreateEndpoints(
|
||||
// template: "{controller}/{action}/{name:alpha}",
|
||||
// defaultValues: null,
|
||||
// handleRequest: true,
|
||||
// constraints: new { name = constraint });
|
||||
|
||||
// var context = CreateLinkGeneratorContext(
|
||||
// var context = CreateRouteValuesContext(
|
||||
// values: new { action = "Index", controller = "Home", name = "products" });
|
||||
|
||||
// // Act
|
||||
// var link = linkGenerator.GetLink(context);
|
||||
// var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// // Assert
|
||||
// Assert.Equal("/Home/Index/products", link);
|
||||
|
|
@ -564,12 +575,12 @@ namespace Microsoft.AspNetCore.Routing
|
|||
{
|
||||
// Arrange
|
||||
var endpoint = CreateEndpoint("{controller}/{action}/{name?}");
|
||||
var linkGenerator = CreateLinkGenerator(CreateEndpointFinder(endpoint));
|
||||
var context = CreateLinkGeneratorContext(
|
||||
var linkGenerator = CreateLinkGenerator();
|
||||
var context = CreateRouteValuesContext(
|
||||
suppliedValues: new { action = "Index", controller = "Home", name = "products" });
|
||||
|
||||
// Act
|
||||
var link = linkGenerator.GetLink(context);
|
||||
var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("/Home/Index/products", link);
|
||||
|
|
@ -580,12 +591,12 @@ namespace Microsoft.AspNetCore.Routing
|
|||
{
|
||||
// Arrange
|
||||
var endpoint = CreateEndpoint("{controller}/{action}/{name?}");
|
||||
var linkGenerator = CreateLinkGenerator(CreateEndpointFinder(endpoint));
|
||||
var context = CreateLinkGeneratorContext(
|
||||
var linkGenerator = CreateLinkGenerator();
|
||||
var context = CreateRouteValuesContext(
|
||||
suppliedValues: new { action = "Index", controller = "Home" });
|
||||
|
||||
// Act
|
||||
var link = linkGenerator.GetLink(context);
|
||||
var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("/Home/Index", link);
|
||||
|
|
@ -598,12 +609,12 @@ namespace Microsoft.AspNetCore.Routing
|
|||
var endpoint = CreateEndpoint(
|
||||
template: "{controller}/{action}/{name?}",
|
||||
defaultValues: new { name = "default-products" });
|
||||
var linkGenerator = CreateLinkGenerator(CreateEndpointFinder(endpoint));
|
||||
var context = CreateLinkGeneratorContext(
|
||||
var linkGenerator = CreateLinkGenerator();
|
||||
var context = CreateRouteValuesContext(
|
||||
suppliedValues: new { action = "Index", controller = "Home", name = "products" });
|
||||
|
||||
// Act
|
||||
var link = linkGenerator.GetLink(context);
|
||||
var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("/Home/Index/products", link);
|
||||
|
|
@ -616,12 +627,12 @@ namespace Microsoft.AspNetCore.Routing
|
|||
var endpoint = CreateEndpoint(
|
||||
template: "{controller}/{action}/{name?}",
|
||||
defaultValues: new { name = "products" });
|
||||
var linkGenerator = CreateLinkGenerator(CreateEndpointFinder(endpoint));
|
||||
var context = CreateLinkGeneratorContext(
|
||||
var linkGenerator = CreateLinkGenerator();
|
||||
var context = CreateRouteValuesContext(
|
||||
suppliedValues: new { action = "Index", controller = "Home" });
|
||||
|
||||
// Act
|
||||
var link = linkGenerator.GetLink(context);
|
||||
var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("/Home/Index", link);
|
||||
|
|
@ -632,12 +643,12 @@ namespace Microsoft.AspNetCore.Routing
|
|||
{
|
||||
// Arrange
|
||||
var endpoint = CreateEndpoint("{controller}/{action}/{name}");
|
||||
var linkGenerator = CreateLinkGenerator(CreateEndpointFinder(endpoint));
|
||||
var context = CreateLinkGeneratorContext(
|
||||
var linkGenerator = CreateLinkGenerator();
|
||||
var context = CreateRouteValuesContext(
|
||||
suppliedValues: new { action = "Index", controller = "Home", name = "products", format = "json" });
|
||||
|
||||
// Act
|
||||
var link = linkGenerator.GetLink(context);
|
||||
var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("/Home/Index/products?format=json", link);
|
||||
|
|
@ -647,17 +658,17 @@ namespace Microsoft.AspNetCore.Routing
|
|||
//public void GetLink_OptionalParameter_FollowedByDotAfterSlash_ParameterPresent()
|
||||
//{
|
||||
// // Arrange
|
||||
// var endpoint = CreateEndpoint(
|
||||
// var endpoint = CreateEndpoints(
|
||||
// template: "{controller}/{action}/.{name?}",
|
||||
// defaultValues: null,
|
||||
// handleRequest: true,
|
||||
// constraints: null);
|
||||
|
||||
// var context = CreateLinkGeneratorContext(
|
||||
// var context = CreateRouteValuesContext(
|
||||
// values: new { action = "Index", controller = "Home", name = "products" });
|
||||
|
||||
// // Act
|
||||
// var link = linkGenerator.GetLink(context);
|
||||
// var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// // Assert
|
||||
// Assert.Equal("/Home/Index/.products", link);
|
||||
|
|
@ -669,17 +680,17 @@ namespace Microsoft.AspNetCore.Routing
|
|||
//public void GetLink_OptionalParameter_FollowedByDotAfterSlash_ParameterNotPresent()
|
||||
//{
|
||||
// // Arrange
|
||||
// var endpoint = CreateEndpoint(
|
||||
// var endpoint = CreateEndpoints(
|
||||
// template: "{controller}/{action}/.{name?}",
|
||||
// defaultValues: null,
|
||||
// handleRequest: true,
|
||||
// constraints: null);
|
||||
|
||||
// var context = CreateLinkGeneratorContext(
|
||||
// var context = CreateRouteValuesContext(
|
||||
// values: new { action = "Index", controller = "Home" });
|
||||
|
||||
// // Act
|
||||
// var link = linkGenerator.GetLink(context);
|
||||
// var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// // Assert
|
||||
// Assert.Equal("/Home/Index/", link);
|
||||
|
|
@ -692,12 +703,12 @@ namespace Microsoft.AspNetCore.Routing
|
|||
{
|
||||
// Arrange
|
||||
var endpoint = CreateEndpoint("{controller}/{action}/{name?}");
|
||||
var linkGenerator = CreateLinkGenerator(CreateEndpointFinder(endpoint));
|
||||
var context = CreateLinkGeneratorContext(
|
||||
var linkGenerator = CreateLinkGenerator();
|
||||
var context = CreateRouteValuesContext(
|
||||
suppliedValues: new { action = "Index", controller = "Home" });
|
||||
|
||||
// Act
|
||||
var link = linkGenerator.GetLink(context);
|
||||
var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("/Home/Index", link);
|
||||
|
|
@ -707,14 +718,14 @@ namespace Microsoft.AspNetCore.Routing
|
|||
//public void GetLink_TwoOptionalParameters_OneValueFromAmbientValues()
|
||||
//{
|
||||
// // Arrange
|
||||
// var endpoint = CreateEndpoint("a/{b=15}/{c?}/{d?}");
|
||||
// var linkGenerator = CreateLinkGenerator(CreateEndpointFinder(endpoint));
|
||||
// var context = CreateLinkGeneratorContext(
|
||||
// var endpoint = CreateEndpoints("a/{b=15}/{c?}/{d?}");
|
||||
// var linkGenerator = CreateLinkGenerator();
|
||||
// var context = CreateRouteValuesContext(
|
||||
// suppliedValues: new { },
|
||||
// ambientValues: new { c = "17" });
|
||||
|
||||
// // Act
|
||||
// var link = linkGenerator.GetLink(context);
|
||||
// var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// // Assert
|
||||
// Assert.Equal("/a/15/17", link);
|
||||
|
|
@ -724,14 +735,14 @@ namespace Microsoft.AspNetCore.Routing
|
|||
//public void GetLink_OptionalParameterAfterDefault_OneValueFromAmbientValues()
|
||||
//{
|
||||
// // Arrange
|
||||
// var endpoint = CreateEndpoint("a/{b=15}/{c?}");
|
||||
// var linkGenerator = CreateLinkGenerator(CreateEndpointFinder(endpoint));
|
||||
// var context = CreateLinkGeneratorContext(
|
||||
// var endpoint = CreateEndpoints("a/{b=15}/{c?}");
|
||||
// var linkGenerator = CreateLinkGenerator();
|
||||
// var context = CreateRouteValuesContext(
|
||||
// suppliedValues: new { },
|
||||
// ambientValues: new { c = "17" });
|
||||
|
||||
// // Act
|
||||
// var link = linkGenerator.GetLink(context);
|
||||
// var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// // Assert
|
||||
// Assert.Equal("/a/15/17", link);
|
||||
|
|
@ -741,18 +752,18 @@ namespace Microsoft.AspNetCore.Routing
|
|||
//public void GetLink_TwoOptionalParametersAfterDefault_LastValueFromAmbientValues()
|
||||
//{
|
||||
// // Arrange
|
||||
// var endpoint = CreateEndpoint(
|
||||
// var endpoint = CreateEndpoints(
|
||||
// template: "a/{b=15}/{c?}/{d?}",
|
||||
// defaultValues: null,
|
||||
// handleRequest: true,
|
||||
// constraints: null);
|
||||
|
||||
// var context = CreateLinkGeneratorContext(
|
||||
// var context = CreateRouteValuesContext(
|
||||
// values: new { },
|
||||
// ambientValues: new { d = "17" });
|
||||
|
||||
// // Act
|
||||
// var link = linkGenerator.GetLink(context);
|
||||
// var link = linkGenerator.GetLink(new[] { endpoint }, context.ExplicitValues, context.AmbientValues);
|
||||
|
||||
// // Assert
|
||||
// Assert.NotNull(pathData);
|
||||
|
|
@ -761,39 +772,32 @@ namespace Microsoft.AspNetCore.Routing
|
|||
//
|
||||
//}
|
||||
|
||||
private LinkGeneratorContext CreateLinkGeneratorContext(object suppliedValues, object ambientValues = null)
|
||||
private RouteValuesBasedEndpointFinderContext CreateRouteValuesContext(object suppliedValues, object ambientValues = null)
|
||||
{
|
||||
var context = new LinkGeneratorContext();
|
||||
context.SuppliedValues = new RouteValueDictionary(suppliedValues);
|
||||
var context = new RouteValuesBasedEndpointFinderContext();
|
||||
context.ExplicitValues = new RouteValueDictionary(suppliedValues);
|
||||
context.AmbientValues = new RouteValueDictionary(ambientValues);
|
||||
return context;
|
||||
}
|
||||
|
||||
private MatcherEndpoint CreateEndpoint(string template, object defaultValues = null)
|
||||
{
|
||||
var defaults = defaultValues == null ? new RouteValueDictionary() : new RouteValueDictionary(defaultValues);
|
||||
return new MatcherEndpoint(
|
||||
next => (httpContext) => Task.CompletedTask,
|
||||
template,
|
||||
defaultValues,
|
||||
defaults,
|
||||
new RouteValueDictionary(),
|
||||
0,
|
||||
EndpointMetadataCollection.Empty,
|
||||
null,
|
||||
new Address("foo"));
|
||||
null);
|
||||
}
|
||||
|
||||
private ILinkGenerator CreateLinkGenerator(IEndpointFinder endpointFinder)
|
||||
private ILinkGenerator CreateLinkGenerator()
|
||||
{
|
||||
return new DefaultLinkGenerator(
|
||||
endpointFinder,
|
||||
new DefaultObjectPool<UriBuildingContext>(new UriBuilderContextPooledObjectPolicy()),
|
||||
Mock.Of<ILogger<DefaultLinkGenerator>>());
|
||||
}
|
||||
|
||||
private DefaultEndpointFinder CreateEndpointFinder(params Endpoint[] endpoints)
|
||||
{
|
||||
return new DefaultEndpointFinder(
|
||||
new CompositeEndpointDataSource(new[] { new DefaultEndpointDataSource(endpoints) }),
|
||||
NullLogger<DefaultEndpointFinder>.Instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,13 +24,11 @@ namespace Microsoft.AspNetCore.Routing.EndpointConstraints
|
|||
// Arrange
|
||||
var defaultEndpoint = new TestEndpoint(
|
||||
EndpointMetadataCollection.Empty,
|
||||
"No constraint endpoint",
|
||||
address: null);
|
||||
"No constraint endpoint");
|
||||
|
||||
var postEndpoint = new TestEndpoint(
|
||||
new EndpointMetadataCollection(new object[] { new HttpMethodEndpointConstraint(new[] { "POST" }) }),
|
||||
"POST constraint endpoint",
|
||||
address: null);
|
||||
"POST constraint endpoint");
|
||||
|
||||
var endpoints = new Endpoint[]
|
||||
{
|
||||
|
|
@ -62,13 +60,11 @@ namespace Microsoft.AspNetCore.Routing.EndpointConstraints
|
|||
|
||||
var defaultEndpoint1 = new TestEndpoint(
|
||||
EndpointMetadataCollection.Empty,
|
||||
"Ambiguous1",
|
||||
address: null);
|
||||
"Ambiguous1");
|
||||
|
||||
var defaultEndpoint2 = new TestEndpoint(
|
||||
EndpointMetadataCollection.Empty,
|
||||
"Ambiguous2",
|
||||
address: null);
|
||||
"Ambiguous2");
|
||||
|
||||
var endpoints = new Endpoint[]
|
||||
{
|
||||
|
|
@ -100,8 +96,8 @@ namespace Microsoft.AspNetCore.Routing.EndpointConstraints
|
|||
|
||||
var actions = new Endpoint[]
|
||||
{
|
||||
new TestEndpoint(EndpointMetadataCollection.Empty, "A1", address: null),
|
||||
new TestEndpoint(EndpointMetadataCollection.Empty, "A2", address: null),
|
||||
new TestEndpoint(EndpointMetadataCollection.Empty, "A1"),
|
||||
new TestEndpoint(EndpointMetadataCollection.Empty, "A2"),
|
||||
};
|
||||
var selector = CreateSelector(actions, loggerFactory);
|
||||
|
||||
|
|
@ -124,13 +120,11 @@ namespace Microsoft.AspNetCore.Routing.EndpointConstraints
|
|||
// Arrange
|
||||
var actionWithConstraints = new TestEndpoint(
|
||||
new EndpointMetadataCollection(new[] { new HttpMethodEndpointConstraint(new string[] { "POST" }) }),
|
||||
"Has constraint",
|
||||
address: null);
|
||||
"Has constraint");
|
||||
|
||||
var actionWithoutConstraints = new TestEndpoint(
|
||||
EndpointMetadataCollection.Empty,
|
||||
"No constraint",
|
||||
address: null);
|
||||
"No constraint");
|
||||
|
||||
var actions = new Endpoint[] { actionWithConstraints, actionWithoutConstraints };
|
||||
|
||||
|
|
@ -150,13 +144,11 @@ namespace Microsoft.AspNetCore.Routing.EndpointConstraints
|
|||
// Arrange
|
||||
var action1 = new TestEndpoint(
|
||||
new EndpointMetadataCollection(new[] { new BooleanConstraint() { Pass = false, } }),
|
||||
"action1",
|
||||
address: null);
|
||||
"action1");
|
||||
|
||||
var action2 = new TestEndpoint(
|
||||
new EndpointMetadataCollection(new[] { new BooleanConstraint() { Pass = false, } }),
|
||||
"action2",
|
||||
address: null);
|
||||
"action2");
|
||||
|
||||
var actions = new Endpoint[] { action1, action2 };
|
||||
|
||||
|
|
@ -179,16 +171,14 @@ namespace Microsoft.AspNetCore.Routing.EndpointConstraints
|
|||
new BooleanConstraint() { Pass = false, Order = 0 },
|
||||
new BooleanConstraint() { Pass = true, Order = 1 },
|
||||
}),
|
||||
"action1",
|
||||
address: null);
|
||||
"action1");
|
||||
|
||||
var action2 = new TestEndpoint(new EndpointMetadataCollection(new[]
|
||||
{
|
||||
new BooleanConstraint() { Pass = true, Order = 0 },
|
||||
new BooleanConstraint() { Pass = false, Order = 1 },
|
||||
}),
|
||||
"action2",
|
||||
address: null);
|
||||
"action2");
|
||||
|
||||
var actions = new Endpoint[] { action1, action2 };
|
||||
|
||||
|
|
@ -213,13 +203,11 @@ namespace Microsoft.AspNetCore.Routing.EndpointConstraints
|
|||
Constraint = new BooleanConstraint() { Pass = true },
|
||||
},
|
||||
}),
|
||||
"actionWithConstraints",
|
||||
address: null);
|
||||
"actionWithConstraints");
|
||||
|
||||
var actionWithoutConstraints = new TestEndpoint(
|
||||
EndpointMetadataCollection.Empty,
|
||||
"actionWithoutConstraints",
|
||||
address: null);
|
||||
"actionWithoutConstraints");
|
||||
|
||||
var actions = new Endpoint[] { actionWithConstraints, actionWithoutConstraints };
|
||||
|
||||
|
|
@ -237,7 +225,7 @@ namespace Microsoft.AspNetCore.Routing.EndpointConstraints
|
|||
public void SelectBestCandidate_MultipleCallsNoConstraint_ReturnsEndpoint()
|
||||
{
|
||||
// Arrange
|
||||
var noConstraint = new TestEndpoint(EndpointMetadataCollection.Empty, "noConstraint", address: null);
|
||||
var noConstraint = new TestEndpoint(EndpointMetadataCollection.Empty, "noConstraint");
|
||||
|
||||
var actions = new Endpoint[] { noConstraint };
|
||||
|
||||
|
|
@ -261,8 +249,7 @@ namespace Microsoft.AspNetCore.Routing.EndpointConstraints
|
|||
{
|
||||
new object(),
|
||||
}),
|
||||
"noConstraint",
|
||||
address: null);
|
||||
"noConstraint");
|
||||
|
||||
var actions = new Endpoint[] { noConstraint };
|
||||
|
||||
|
|
@ -286,8 +273,7 @@ namespace Microsoft.AspNetCore.Routing.EndpointConstraints
|
|||
{
|
||||
new ConstraintFactory(),
|
||||
}),
|
||||
"nullConstraint",
|
||||
address: null);
|
||||
"nullConstraint");
|
||||
|
||||
var actions = new Endpoint[] { nullConstraint };
|
||||
|
||||
|
|
@ -312,13 +298,11 @@ namespace Microsoft.AspNetCore.Routing.EndpointConstraints
|
|||
{
|
||||
new BooleanConstraintMarker() { Pass = true },
|
||||
}),
|
||||
"actionWithConstraints",
|
||||
address: null);
|
||||
"actionWithConstraints");
|
||||
|
||||
var actionWithoutConstraints = new TestEndpoint(
|
||||
EndpointMetadataCollection.Empty,
|
||||
"actionWithoutConstraints",
|
||||
address: null);
|
||||
"actionWithoutConstraints");
|
||||
|
||||
var actions = new Endpoint[] { actionWithConstraints, actionWithoutConstraints, };
|
||||
|
||||
|
|
@ -341,15 +325,13 @@ namespace Microsoft.AspNetCore.Routing.EndpointConstraints
|
|||
{
|
||||
new BooleanConstraint() { Pass = true, Order = 0, },
|
||||
}),
|
||||
"best",
|
||||
address: null);
|
||||
"best");
|
||||
|
||||
var worst = new TestEndpoint(new EndpointMetadataCollection(new[]
|
||||
{
|
||||
new BooleanConstraint() { Pass = true, Order = 1, },
|
||||
}),
|
||||
"worst",
|
||||
address: null);
|
||||
"worst");
|
||||
|
||||
var actions = new Endpoint[] { best, worst };
|
||||
|
||||
|
|
@ -374,8 +356,7 @@ namespace Microsoft.AspNetCore.Routing.EndpointConstraints
|
|||
new BooleanConstraint() { Pass = true, Order = 1, },
|
||||
new BooleanConstraint() { Pass = true, Order = 2, },
|
||||
}),
|
||||
"best",
|
||||
address: null);
|
||||
"best");
|
||||
|
||||
var worst = new TestEndpoint(new EndpointMetadataCollection(new[]
|
||||
{
|
||||
|
|
@ -383,8 +364,7 @@ namespace Microsoft.AspNetCore.Routing.EndpointConstraints
|
|||
new BooleanConstraint() { Pass = true, Order = 1, },
|
||||
new BooleanConstraint() { Pass = true, Order = 3, },
|
||||
}),
|
||||
"worst",
|
||||
address: null);
|
||||
"worst");
|
||||
|
||||
var actions = new Endpoint[] { best, worst };
|
||||
|
||||
|
|
@ -408,8 +388,7 @@ namespace Microsoft.AspNetCore.Routing.EndpointConstraints
|
|||
new BooleanConstraint() { Pass = true, Order = 1, },
|
||||
new BooleanConstraint() { Pass = false, Order = 2, },
|
||||
}),
|
||||
"nomatch1",
|
||||
address: null);
|
||||
"nomatch1");
|
||||
|
||||
var nomatch2 = new TestEndpoint(new EndpointMetadataCollection(new[]
|
||||
{
|
||||
|
|
@ -417,10 +396,9 @@ namespace Microsoft.AspNetCore.Routing.EndpointConstraints
|
|||
new BooleanConstraint() { Pass = true, Order = 1, },
|
||||
new BooleanConstraint() { Pass = false, Order = 3, },
|
||||
}),
|
||||
"nomatch2",
|
||||
address: null);
|
||||
"nomatch2");
|
||||
|
||||
var best = new TestEndpoint(EndpointMetadataCollection.Empty, "best", address: null);
|
||||
var best = new TestEndpoint(EndpointMetadataCollection.Empty, "best");
|
||||
|
||||
var actions = new Endpoint[] { best, nomatch1, nomatch2 };
|
||||
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ namespace Microsoft.AspNetCore.Routing.Internal
|
|||
var context = new EndpointConstraintContext();
|
||||
|
||||
var endpointSelectorCandidate = new EndpointSelectorCandidate(
|
||||
new TestEndpoint(EndpointMetadataCollection.Empty, string.Empty, address: null),
|
||||
new TestEndpoint(EndpointMetadataCollection.Empty, string.Empty),
|
||||
new List<IEndpointConstraint> { constraint });
|
||||
|
||||
context.Candidates = new List<EndpointSelectorCandidate> { endpointSelectorCandidate };
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ namespace Microsoft.AspNetCore.Routing.Internal.Routing
|
|||
var context = CreateContext(new { });
|
||||
|
||||
// Act
|
||||
var matches = tree.GetMatches(context);
|
||||
var matches = tree.GetMatches(context.Values, context.AmbientValues);
|
||||
|
||||
// Assert
|
||||
Assert.Same(entry, Assert.Single(matches).Match);
|
||||
|
|
@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Routing.Internal.Routing
|
|||
var context = CreateContext(new { controller = "Store", action = "Buy" });
|
||||
|
||||
// Act
|
||||
var matches = tree.GetMatches(context);
|
||||
var matches = tree.GetMatches(context.Values, context.AmbientValues);
|
||||
|
||||
// Assert
|
||||
Assert.Same(entry, Assert.Single(matches).Match);
|
||||
|
|
@ -66,7 +66,7 @@ namespace Microsoft.AspNetCore.Routing.Internal.Routing
|
|||
var context = CreateContext(values: null, ambientValues: new { controller = "Store", action = "Buy" });
|
||||
|
||||
// Act
|
||||
var matches = tree.GetMatches(context);
|
||||
var matches = tree.GetMatches(context.Values, context.AmbientValues);
|
||||
|
||||
// Assert
|
||||
var match = Assert.Single(matches);
|
||||
|
|
@ -90,7 +90,7 @@ namespace Microsoft.AspNetCore.Routing.Internal.Routing
|
|||
ambientValues: new { controller = "Store", action = "Cart" });
|
||||
|
||||
// Act
|
||||
var matches = tree.GetMatches(context);
|
||||
var matches = tree.GetMatches(context.Values, context.AmbientValues);
|
||||
|
||||
// Assert
|
||||
var match = Assert.Single(matches);
|
||||
|
|
@ -114,7 +114,7 @@ namespace Microsoft.AspNetCore.Routing.Internal.Routing
|
|||
ambientValues: new { controller = "Store", action = "Buy" });
|
||||
|
||||
// Act
|
||||
var matches = tree.GetMatches(context);
|
||||
var matches = tree.GetMatches(context.Values, context.AmbientValues);
|
||||
|
||||
// Assert
|
||||
var match = Assert.Single(matches);
|
||||
|
|
@ -136,7 +136,7 @@ namespace Microsoft.AspNetCore.Routing.Internal.Routing
|
|||
var context = CreateContext(new { controller = "Store", action = "AddToCart" });
|
||||
|
||||
// Act
|
||||
var matches = tree.GetMatches(context);
|
||||
var matches = tree.GetMatches(context.Values, context.AmbientValues);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(matches);
|
||||
|
|
@ -158,7 +158,7 @@ namespace Microsoft.AspNetCore.Routing.Internal.Routing
|
|||
ambientValues: new { controller = "Store", action = "Cart" });
|
||||
|
||||
// Act
|
||||
var matches = tree.GetMatches(context);
|
||||
var matches = tree.GetMatches(context.Values, context.AmbientValues);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(matches);
|
||||
|
|
@ -183,7 +183,7 @@ namespace Microsoft.AspNetCore.Routing.Internal.Routing
|
|||
ambientValues: new { controller = "Store", action = "Buy" });
|
||||
|
||||
// Act
|
||||
var matches = tree.GetMatches(context);
|
||||
var matches = tree.GetMatches(context.Values, context.AmbientValues);
|
||||
|
||||
// Assert
|
||||
Assert.Same(entry1, Assert.Single(matches).Match);
|
||||
|
|
@ -209,7 +209,7 @@ namespace Microsoft.AspNetCore.Routing.Internal.Routing
|
|||
ambientValues: new { controller = "Store", action = "Buy" });
|
||||
|
||||
// Act
|
||||
var matches = tree.GetMatches(context).Select(m => m.Match).ToList();
|
||||
var matches = tree.GetMatches(context.Values, context.AmbientValues).Select(m => m.Match).ToList();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(entries, matches);
|
||||
|
|
@ -233,7 +233,7 @@ namespace Microsoft.AspNetCore.Routing.Internal.Routing
|
|||
var context = CreateContext(new { controller = "Store", action = "Buy", slug = "1234" });
|
||||
|
||||
// Act
|
||||
var matches = tree.GetMatches(context).Select(m => m.Match).ToList();
|
||||
var matches = tree.GetMatches(context.Values, context.AmbientValues).Select(m => m.Match).ToList();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(entries, matches);
|
||||
|
|
@ -260,7 +260,7 @@ namespace Microsoft.AspNetCore.Routing.Internal.Routing
|
|||
var context = CreateContext(new { controller = "Store", action = "Buy" });
|
||||
|
||||
// Act
|
||||
var matches = tree.GetMatches(context).Select(m => m.Match).ToList();
|
||||
var matches = tree.GetMatches(context.Values, context.AmbientValues).Select(m => m.Match).ToList();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(entries, matches);
|
||||
|
|
@ -286,7 +286,7 @@ namespace Microsoft.AspNetCore.Routing.Internal.Routing
|
|||
var context = CreateContext(new { controller = "Store", action = "Buy" });
|
||||
|
||||
// Act
|
||||
var matches = tree.GetMatches(context).Select(m => m.Match).ToList();
|
||||
var matches = tree.GetMatches(context.Values, context.AmbientValues).Select(m => m.Match).ToList();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(entries, matches);
|
||||
|
|
@ -312,7 +312,7 @@ namespace Microsoft.AspNetCore.Routing.Internal.Routing
|
|||
var context = CreateContext(new { controller = "Store", action = "Buy" });
|
||||
|
||||
// Act
|
||||
var matches = tree.GetMatches(context).Select(m => m.Match).ToList();
|
||||
var matches = tree.GetMatches(context.Values, context.AmbientValues).Select(m => m.Match).ToList();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(entries, matches);
|
||||
|
|
|
|||
|
|
@ -34,17 +34,18 @@ namespace Microsoft.AspNetCore.Routing.Matchers
|
|||
|
||||
internal static MatcherEndpoint CreateEndpoint(
|
||||
string template,
|
||||
object defaults = null,
|
||||
object defaultValues = null,
|
||||
int? order = null)
|
||||
{
|
||||
var defaults = defaultValues == null ? new RouteValueDictionary() : new RouteValueDictionary(defaultValues);
|
||||
return new MatcherEndpoint(
|
||||
MatcherEndpoint.EmptyInvoker,
|
||||
template,
|
||||
defaults,
|
||||
new RouteValueDictionary(),
|
||||
order ?? 0,
|
||||
EndpointMetadataCollection.Empty,
|
||||
"endpoint: " + template,
|
||||
address: null);
|
||||
"endpoint: " + template);
|
||||
}
|
||||
|
||||
internal (Matcher matcher, MatcherEndpoint endpoint) CreateMatcher(string template)
|
||||
|
|
|
|||
|
|
@ -31,10 +31,10 @@ namespace Microsoft.AspNetCore.Routing.Matchers
|
|||
// MatcherEndpoint.Values contains the default values parsed from the template
|
||||
// as well as those specified with a literal. We need to separate those
|
||||
// for legacy cases.
|
||||
var defaults = new RouteValueDictionary(endpoint.Values);
|
||||
for (var i = 0; i < endpoint.ParsedTemlate.Parameters.Count; i++)
|
||||
var defaults = endpoint.Defaults;
|
||||
for (var i = 0; i < endpoint.ParsedTemplate.Parameters.Count; i++)
|
||||
{
|
||||
var parameter = endpoint.ParsedTemlate.Parameters[i];
|
||||
var parameter = endpoint.ParsedTemplate.Parameters[i];
|
||||
if (parameter.DefaultValue != null)
|
||||
{
|
||||
defaults.Remove(parameter.Name);
|
||||
|
|
@ -79,7 +79,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
|
|||
return comparison;
|
||||
}
|
||||
|
||||
comparison = RoutePrecedence.ComputeInbound(Endpoint.ParsedTemlate).CompareTo(RoutePrecedence.ComputeInbound(other.Endpoint.ParsedTemlate));
|
||||
comparison = RoutePrecedence.ComputeInbound(Endpoint.ParsedTemplate).CompareTo(RoutePrecedence.ComputeInbound(other.Endpoint.ParsedTemplate));
|
||||
if (comparison != 0)
|
||||
{
|
||||
return comparison;
|
||||
|
|
|
|||
|
|
@ -1,23 +1,22 @@
|
|||
// 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 System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing.EndpointConstraints;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing.Matchers
|
||||
{
|
||||
public class TreeMatcherTests
|
||||
{
|
||||
private MatcherEndpoint CreateEndpoint(string template, int order, object values = null, EndpointMetadataCollection metadata = null)
|
||||
private MatcherEndpoint CreateEndpoint(string template, int order, object defaultValues = null, EndpointMetadataCollection metadata = null)
|
||||
{
|
||||
return new MatcherEndpoint((next) => null, template, values, order, metadata ?? EndpointMetadataCollection.Empty, template, address: null);
|
||||
var defaults = defaultValues == null ? new RouteValueDictionary() : new RouteValueDictionary(defaultValues);
|
||||
return new MatcherEndpoint((next) => null, template, defaults, new RouteValueDictionary(), order, metadata ?? EndpointMetadataCollection.Empty, template);
|
||||
}
|
||||
|
||||
private TreeMatcher CreateTreeMatcher(EndpointDataSource endpointDataSource)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Routing.Internal;
|
||||
using Microsoft.AspNetCore.Routing.Template;
|
||||
using Microsoft.AspNetCore.Routing.Tree;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.ObjectPool;
|
||||
|
|
@ -38,10 +37,10 @@ namespace Microsoft.AspNetCore.Routing.Matchers
|
|||
// MatcherEndpoint.Values contains the default values parsed from the template
|
||||
// as well as those specified with a literal. We need to separate those
|
||||
// for legacy cases.
|
||||
var defaults = new RouteValueDictionary(endpoint.Values);
|
||||
for (var i = 0; i < endpoint.ParsedTemlate.Parameters.Count; i++)
|
||||
var defaults = endpoint.Defaults;
|
||||
for (var i = 0; i < endpoint.ParsedTemplate.Parameters.Count; i++)
|
||||
{
|
||||
var parameter = endpoint.ParsedTemlate.Parameters[i];
|
||||
var parameter = endpoint.ParsedTemplate.Parameters[i];
|
||||
if (parameter.DefaultValue == null && defaults.ContainsKey(parameter.Name))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
|
|
@ -50,8 +49,8 @@ namespace Microsoft.AspNetCore.Routing.Matchers
|
|||
}
|
||||
|
||||
_inner.MapInbound(
|
||||
handler,
|
||||
endpoint.ParsedTemlate,
|
||||
handler,
|
||||
endpoint.ParsedTemplate,
|
||||
routeName: null,
|
||||
order: endpoint.Order);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ namespace Microsoft.AspNetCore.Routing.TestObjects
|
|||
{
|
||||
internal class TestEndpoint : Endpoint
|
||||
{
|
||||
public TestEndpoint(EndpointMetadataCollection metadata, string displayName, Address address)
|
||||
: base(metadata, displayName, address)
|
||||
public TestEndpoint(EndpointMetadataCollection metadata, string displayName)
|
||||
: base(metadata, displayName)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
// 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 System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing.Matchers;
|
||||
|
|
@ -22,7 +20,7 @@ namespace Microsoft.AspNetCore.Routing.TestObjects
|
|||
{
|
||||
if (_isHandled)
|
||||
{
|
||||
feature.Endpoint = new TestEndpoint(EndpointMetadataCollection.Empty, "Test endpoint", address: null);
|
||||
feature.Endpoint = new TestEndpoint(EndpointMetadataCollection.Empty, "Test endpoint");
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
|
|
|
|||
Loading…
Reference in New Issue