Added a RouteValuesBasedEndpointFinder

This commit is contained in:
Kiran Challa 2018-06-25 12:21:15 -07:00
parent bc5f02444b
commit 1009705283
30 changed files with 502 additions and 502 deletions

View File

@ -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"),
}));
});
}

View File

@ -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)

View File

@ -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"),
}));
});
}

View File

@ -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; }
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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; }
}
}

View File

@ -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; }
}
}

View File

@ -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>();
}
}
}

View File

@ -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.

View File

@ -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

View File

@ -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);
}
}

View File

@ -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)
{

View File

@ -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))
{

View File

@ -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>();
}
}
}

View File

@ -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();
}
}
}
}

View File

@ -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; }
}
}

View File

@ -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; }
}
}

View File

@ -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)
{

View File

@ -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() { }
}
}
}

View File

@ -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);
}
}
}

View File

@ -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 };

View File

@ -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 };

View File

@ -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);

View File

@ -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)

View File

@ -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;

View File

@ -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)

View File

@ -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);
}

View File

@ -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)
{
}
}

View File

@ -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;