Change endpoint invoker to RequestDelegate, Endpoint/EndpointMetadataCollection namespaces, split out IRouteValuesFeature (#712)

This commit is contained in:
James Newton-King 2018-08-22 17:15:57 +12:00 committed by GitHub
parent 08a0a7fadb
commit 1680b9f4fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
89 changed files with 574 additions and 501 deletions

View File

@ -2,9 +2,9 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Text;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Internal;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Routing.Matching;
using Microsoft.AspNetCore.Routing.Patterns;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
@ -21,8 +21,8 @@ namespace Benchmarks
var endpointDataSource = new DefaultEndpointDataSource(new[]
{
new MatcherEndpoint(
invoker: (next) => (httpContext) =>
new RouteEndpoint(
requestDelegate: (httpContext) =>
{
var response = httpContext.Response;
var payloadLength = _helloWorldPayload.Length;

View File

@ -3,6 +3,7 @@
using System;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Routing
{

View File

@ -5,7 +5,9 @@ using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing.Matching;
using Microsoft.AspNetCore.Routing.Patterns;
using Microsoft.AspNetCore.Routing.Template;
@ -18,10 +20,10 @@ namespace Microsoft.AspNetCore.Routing
{
public abstract class EndpointRoutingBenchmarkBase
{
private protected MatcherEndpoint[] Endpoints;
private protected RouteEndpoint[] Endpoints;
private protected HttpContext[] Requests;
private protected void SetupEndpoints(params MatcherEndpoint[] endpoints)
private protected void SetupEndpoints(params RouteEndpoint[] endpoints)
{
Endpoints = endpoints;
}
@ -76,8 +78,8 @@ namespace Microsoft.AspNetCore.Routing
var message = new StringBuilder();
message.AppendLine($"Validation failed for request {Array.IndexOf(Requests, httpContext)}");
message.AppendLine($"{httpContext.Request.Method} {httpContext.Request.Path}");
message.AppendLine($"expected: '{((MatcherEndpoint)expected)?.DisplayName ?? "null"}'");
message.AppendLine($"actual: '{((MatcherEndpoint)actual)?.DisplayName ?? "null"}'");
message.AppendLine($"expected: '{((RouteEndpoint)expected)?.DisplayName ?? "null"}'");
message.AppendLine($"actual: '{((RouteEndpoint)actual)?.DisplayName ?? "null"}'");
throw new InvalidOperationException(message.ToString());
}
}
@ -95,7 +97,7 @@ namespace Microsoft.AspNetCore.Routing
}
}
protected MatcherEndpoint CreateEndpoint(
protected RouteEndpoint CreateEndpoint(
string template,
object defaults = null,
object constraints = null,
@ -108,8 +110,8 @@ namespace Microsoft.AspNetCore.Routing
var endpointMetadata = new List<object>(metadata ?? Array.Empty<object>());
endpointMetadata.Add(new RouteValuesAddressMetadata(routeName, new RouteValueDictionary(requiredValues)));
return new MatcherEndpoint(
MatcherEndpoint.EmptyInvoker,
return new RouteEndpoint(
(context) => Task.CompletedTask,
RoutePatternFactory.Parse(template, defaults, constraints),
order,
new EndpointMetadataCollection(endpointMetadata),
@ -119,14 +121,15 @@ namespace Microsoft.AspNetCore.Routing
protected (HttpContext httpContext, RouteValueDictionary ambientValues) CreateCurrentRequestContext(
object ambientValues = null)
{
var feature = new EndpointFeature { Values = new RouteValueDictionary(ambientValues) };
var feature = new EndpointFeature { RouteValues = new RouteValueDictionary(ambientValues) };
var context = new DefaultHttpContext();
context.Features.Set<IEndpointFeature>(feature);
context.Features.Set<IRouteValuesFeature>(feature);
return (context, feature.Values);
return (context, feature.RouteValues);
}
protected void CreateOutboundRouteEntry(TreeRouteBuilder treeRouteBuilder, MatcherEndpoint endpoint)
protected void CreateOutboundRouteEntry(TreeRouteBuilder treeRouteBuilder, RouteEndpoint endpoint)
{
var routeValuesAddressMetadata = endpoint.Metadata.GetMetadata<IRouteValuesAddressMetadata>();
var requiredValues = routeValuesAddressMetadata?.RequiredValues ?? new RouteValueDictionary();

View File

@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Routing.LinkGeneration
private void SetupEndpoints()
{
Endpoints = new MatcherEndpoint[243];
Endpoints = new RouteEndpoint[243];
Endpoints[0] = CreateEndpoint("/emojis", "Controller1", "Action1", "GET");
Endpoints[1] = CreateEndpoint("/events", "Controller2", "Action1", "GET");
Endpoints[2] = CreateEndpoint("/feeds", "Controller3", "Action1", "GET");
@ -1485,7 +1485,7 @@ namespace Microsoft.AspNetCore.Routing.LinkGeneration
return builder.Build();
}
private MatcherEndpoint CreateEndpoint(string template, string controllerName, string actionName, string httpMethod)
private RouteEndpoint CreateEndpoint(string template, string controllerName, string actionName, string httpMethod)
{
var requiredValues = new
{

View File

@ -3,6 +3,7 @@
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Http.Features;
namespace Microsoft.AspNetCore.Routing.Matching
{

View File

@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
private void SetupEndpoints()
{
Endpoints = new MatcherEndpoint[5160];
Endpoints = new RouteEndpoint[5160];
Endpoints[0] = CreateEndpoint("/account", "GET");
Endpoints[1] = CreateEndpoint("/analyze", "POST");
Endpoints[2] = CreateEndpoint("/apis", "GET");

View File

@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
private void SetupEndpoints()
{
Endpoints = new MatcherEndpoint[3517];
Endpoints = new RouteEndpoint[3517];
Endpoints[0] = CreateEndpoint("/account");
Endpoints[1] = CreateEndpoint("/analyze");
Endpoints[2] = CreateEndpoint("/apis");

View File

@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
private void SetupEndpoints()
{
Endpoints = new MatcherEndpoint[155];
Endpoints = new RouteEndpoint[155];
Endpoints[0] = CreateEndpoint("/emojis");
Endpoints[1] = CreateEndpoint("/events");
Endpoints[2] = CreateEndpoint("/feeds");

View File

@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
[GlobalSetup]
public void Setup()
{
Endpoints = new MatcherEndpoint[1];
Endpoints = new RouteEndpoint[1];
Endpoints[0] = CreateEndpoint("/plaintext");
Requests = new HttpContext[1];

View File

@ -4,6 +4,7 @@
using System;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
namespace Microsoft.AspNetCore.Routing.Matching
{
@ -32,7 +33,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
private void SetupEndpoints()
{
Endpoints = new MatcherEndpoint[10];
Endpoints = new RouteEndpoint[10];
Endpoints[0] = CreateEndpoint("/another-really-cool-entry");
Endpoints[1] = CreateEndpoint("/Some-Entry");
Endpoints[2] = CreateEndpoint("/a/path/with/more/segments");

View File

@ -3,6 +3,7 @@
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Http.Features;
namespace Microsoft.AspNetCore.Routing.Matching
{

View File

@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
private void SetupEndpoints()
{
Endpoints = new MatcherEndpoint[243];
Endpoints = new RouteEndpoint[243];
Endpoints[0] = CreateEndpoint("/emojis", "GET");
Endpoints[1] = CreateEndpoint("/events", "GET");
Endpoints[2] = CreateEndpoint("/feeds", "GET");

View File

@ -4,6 +4,7 @@
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
namespace Microsoft.AspNetCore.Routing.Matching
{
@ -22,7 +23,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
[GlobalSetup]
public void Setup()
{
Endpoints = new MatcherEndpoint[1];
Endpoints = new RouteEndpoint[1];
Endpoints[0] = CreateEndpoint("/plaintext");
Requests = new HttpContext[1];

View File

@ -4,6 +4,7 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
namespace Microsoft.AspNetCore.Routing.Matching
{
@ -12,17 +13,17 @@ namespace Microsoft.AspNetCore.Routing.Matching
// to establish a lower bound for perf comparisons.
internal sealed class TrivialMatcher : Matcher
{
private readonly MatcherEndpoint _endpoint;
private readonly RouteEndpoint _endpoint;
private readonly Candidate[] _candidates;
public TrivialMatcher(MatcherEndpoint endpoint)
public TrivialMatcher(RouteEndpoint endpoint)
{
_endpoint = endpoint;
_candidates = new Candidate[] { new Candidate(endpoint), };
}
public sealed override Task MatchAsync(HttpContext httpContext, IEndpointFeature feature)
public sealed override Task MatchAsync(HttpContext httpContext, EndpointFeature feature)
{
if (httpContext == null)
{
@ -38,7 +39,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
if (string.Equals(_endpoint.RoutePattern.RawText, path, StringComparison.OrdinalIgnoreCase))
{
feature.Endpoint = _endpoint;
feature.Values = new RouteValueDictionary();
feature.RouteValues = new RouteValueDictionary();
}
return Task.CompletedTask;

View File

@ -8,9 +8,9 @@ namespace Microsoft.AspNetCore.Routing.Matching
{
internal class TrivialMatcherBuilder : MatcherBuilder
{
private readonly List<MatcherEndpoint> _endpoints = new List<MatcherEndpoint>();
private readonly List<RouteEndpoint> _endpoints = new List<RouteEndpoint>();
public override void AddEndpoint(MatcherEndpoint endpoint)
public override void AddEndpoint(RouteEndpoint endpoint)
{
_endpoints.Add(endpoint);
}

View File

@ -78,7 +78,7 @@ namespace Microsoft.AspNetCore.Routing
private void SetupEndpoints()
{{
Endpoints = new MatcherEndpoint[{3}];
Endpoints = new RouteEndpoint[{3}];
{0}
}}
@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.Routing
return builder.Build();
}}
private MatcherEndpoint CreateEndpoint(string template, string controllerName, string actionName, string httpMethod)
private RouteEndpoint CreateEndpoint(string template, string controllerName, string actionName, string httpMethod)
{{
var requiredValues = new
{{

View File

@ -32,7 +32,7 @@ namespace RoutingSample.Web
var endpointDataSource = new DefaultEndpointDataSource(new[]
{
new MatcherEndpoint((next) => (httpContext) =>
new RouteEndpoint((httpContext) =>
{
var response = httpContext.Response;
var payloadLength = _homePayload.Length;
@ -45,7 +45,7 @@ namespace RoutingSample.Web
0,
EndpointMetadataCollection.Empty,
"Home"),
new MatcherEndpoint((next) => (httpContext) =>
new RouteEndpoint((httpContext) =>
{
var response = httpContext.Response;
var payloadLength = _helloWorldPayload.Length;
@ -58,7 +58,7 @@ namespace RoutingSample.Web
0,
EndpointMetadataCollection.Empty,
"Plaintext"),
new MatcherEndpoint((next) => (httpContext) =>
new RouteEndpoint((httpContext) =>
{
var response = httpContext.Response;
response.StatusCode = 200;
@ -69,7 +69,7 @@ namespace RoutingSample.Web
0,
EndpointMetadataCollection.Empty,
"withconstraints"),
new MatcherEndpoint((next) => (httpContext) =>
new RouteEndpoint((httpContext) =>
{
var response = httpContext.Response;
response.StatusCode = 200;
@ -80,7 +80,7 @@ namespace RoutingSample.Web
0,
EndpointMetadataCollection.Empty,
"withoptionalconstraints"),
new MatcherEndpoint((next) => (httpContext) =>
new RouteEndpoint((httpContext) =>
{
using (var writer = new StreamWriter(httpContext.Response.Body, Encoding.UTF8, 1024, leaveOpen: true))
{
@ -95,7 +95,7 @@ namespace RoutingSample.Web
0,
new EndpointMetadataCollection(new HttpMethodMetadata(new[]{ "GET", })),
"DFA Graph"),
new MatcherEndpoint((next) => (httpContext) =>
new RouteEndpoint((httpContext) =>
{
var linkGenerator = httpContext.RequestServices.GetRequiredService<LinkGenerator>();
@ -112,7 +112,7 @@ namespace RoutingSample.Web
name: "WithSingleAsteriskCatchAll",
requiredValues: new RouteValueDictionary())),
"WithSingleAsteriskCatchAll"),
new MatcherEndpoint((next) => (httpContext) =>
new RouteEndpoint((httpContext) =>
{
var linkGenerator = httpContext.RequestServices.GetRequiredService<LinkGenerator>();

View File

@ -1,27 +1,30 @@
// 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.Http
{
/// <summary>
/// Respresents a logical endpoint in an application.
/// </summary>
public abstract class Endpoint
public class Endpoint
{
/// <summary>
/// Creates a new instance of <see cref="Endpoint"/>.
/// </summary>
/// <param name="requestDelegate">The delegate used to process requests for the endpoint.</param>
/// <param name="metadata">
/// The endpoint <see cref="EndpointMetadataCollection"/>. May be null.
/// </param>
/// <param name="displayName">
/// The informational display name of the endpoint. May be null.
/// </param>
protected Endpoint(
public Endpoint(
RequestDelegate requestDelegate,
EndpointMetadataCollection metadata,
string displayName)
{
// All are allowed to be null
RequestDelegate = requestDelegate;
Metadata = metadata ?? EndpointMetadataCollection.Empty;
DisplayName = displayName;
}
@ -36,6 +39,11 @@ namespace Microsoft.AspNetCore.Routing
/// </summary>
public EndpointMetadataCollection Metadata { get; }
/// <summary>
/// Gets the delegate used to process requests for the endpoint.
/// </summary>
public RequestDelegate RequestDelegate { get; }
public override string ToString() => DisplayName ?? base.ToString();
}
}

View File

@ -8,7 +8,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
namespace Microsoft.AspNetCore.Routing
namespace Microsoft.AspNetCore.Http
{
/// <summary>
/// A collection of arbitrary metadata associated with an endpoint.

View File

@ -1,10 +1,7 @@
// 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 Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Routing
namespace Microsoft.AspNetCore.Http.Features
{
/// <summary>
/// A feature interface for endpoint routing. Use <see cref="HttpContext.Features"/>
@ -13,21 +10,9 @@ namespace Microsoft.AspNetCore.Routing
public interface IEndpointFeature
{
/// <summary>
/// Gets or sets the selected <see cref="Routing.Endpoint"/> for the current
/// Gets or sets the selected <see cref="Http.Endpoint"/> for the current
/// request.
/// </summary>
Endpoint Endpoint { get; set; }
/// <summary>
/// Gets or sets a delegate that can be used to invoke the current
/// <see cref="Routing.Endpoint"/>.
/// </summary>
Func<RequestDelegate, RequestDelegate> Invoker { get; set; }
/// <summary>
/// Gets or sets the <see cref="RouteValueDictionary"/> associated with the currrent
/// request.
/// </summary>
RouteValueDictionary Values { get; set; }
}
}

View File

@ -0,0 +1,16 @@
// 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;
namespace Microsoft.AspNetCore.Http.Features
{
public interface IRouteValuesFeature
{
/// <summary>
/// Gets or sets the <see cref="RouteValueDictionary"/> associated with the currrent
/// request.
/// </summary>
RouteValueDictionary RouteValues { get; set; }
}
}

View File

@ -7,7 +7,7 @@ using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using Microsoft.AspNetCore.Routing.Matching;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNetCore.Routing
@ -132,15 +132,15 @@ namespace Microsoft.AspNetCore.Routing
var sb = new StringBuilder();
foreach (var endpoint in _endpoints)
{
if (endpoint is MatcherEndpoint matcherEndpoint)
if (endpoint is RouteEndpoint routeEndpoint)
{
var template = matcherEndpoint.RoutePattern.RawText;
var template = routeEndpoint.RoutePattern.RawText;
template = string.IsNullOrEmpty(template) ? "\"\"" : template;
sb.Append(template);
sb.Append(", Defaults: new { ");
sb.Append(string.Join(", ", FormatValues(matcherEndpoint.RoutePattern.Defaults)));
sb.Append(string.Join(", ", FormatValues(routeEndpoint.RoutePattern.Defaults)));
sb.Append(" }");
var routeValuesAddressMetadata = matcherEndpoint.Metadata.GetMetadata<IRouteValuesAddressMetadata>();
var routeValuesAddressMetadata = routeEndpoint.Metadata.GetMetadata<IRouteValuesAddressMetadata>();
sb.Append(", Route Name: ");
sb.Append(routeValuesAddressMetadata?.Name);
if (routeValuesAddressMetadata?.RequiredValues != null)
@ -150,21 +150,21 @@ namespace Microsoft.AspNetCore.Routing
sb.Append(" }");
}
sb.Append(", Order: ");
sb.Append(matcherEndpoint.Order);
sb.Append(routeEndpoint.Order);
var httpMethodMetadata = matcherEndpoint.Metadata.GetMetadata<IHttpMethodMetadata>();
var httpMethodMetadata = routeEndpoint.Metadata.GetMetadata<IHttpMethodMetadata>();
if (httpMethodMetadata != null)
{
sb.Append(", Http Methods: ");
sb.Append(string.Join(", ", httpMethodMetadata.HttpMethods));
}
sb.Append(", Display Name: ");
sb.Append(matcherEndpoint.DisplayName);
sb.Append(routeEndpoint.DisplayName);
sb.AppendLine();
}
else
{
sb.Append("Non-MatcherEndpoint. DisplayName:");
sb.Append("Non-RouteEndpoint. DisplayName:");
sb.AppendLine(endpoint.DisplayName);
}
}

View File

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Threading;
using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Routing
{

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Routing
{

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Primitives;

View File

@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Routing
{
public DefaultLinkGenerationTemplate(
DefaultLinkGenerator linkGenerator,
IEnumerable<MatcherEndpoint> endpoints,
IEnumerable<RouteEndpoint> endpoints,
HttpContext httpContext,
RouteValueDictionary explicitValues,
RouteValueDictionary ambientValues)
@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Routing
internal DefaultLinkGenerator LinkGenerator { get; }
internal IEnumerable<MatcherEndpoint> Endpoints { get; }
internal IEnumerable<RouteEndpoint> Endpoints { get; }
internal HttpContext HttpContext { get; }

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing.Internal;
using Microsoft.AspNetCore.Routing.Matching;
using Microsoft.AspNetCore.Routing.Template;
@ -97,7 +98,7 @@ namespace Microsoft.AspNetCore.Routing
internal string MakeLink(
HttpContext httpContext,
MatcherEndpoint endpoint,
RouteEndpoint endpoint,
RouteValueDictionary ambientValues,
RouteValueDictionary explicitValues,
LinkOptions options)
@ -232,7 +233,7 @@ namespace Microsoft.AspNetCore.Routing
private bool MatchesConstraints(
HttpContext httpContext,
MatcherEndpoint endpoint,
RouteEndpoint endpoint,
RouteValueDictionary routeValues)
{
if (routeValues == null)
@ -303,16 +304,16 @@ namespace Microsoft.AspNetCore.Routing
{
if (httpContext != null)
{
var feature = httpContext.Features.Get<IEndpointFeature>();
var feature = httpContext.Features.Get<IRouteValuesFeature>();
if (feature != null)
{
return feature.Values;
return feature.RouteValues;
}
}
return new RouteValueDictionary();
}
private IEnumerable<MatcherEndpoint> FindEndpoints<TAddress>(TAddress address)
private IEnumerable<RouteEndpoint> FindEndpoints<TAddress>(TAddress address)
{
var finder = _serviceProvider.GetRequiredService<IEndpointFinder<TAddress>>();
var endpoints = finder.FindEndpoints(address);
@ -321,13 +322,13 @@ namespace Microsoft.AspNetCore.Routing
return null;
}
var matcherEndpoints = endpoints.OfType<MatcherEndpoint>();
if (!matcherEndpoints.Any())
var routeEndpoints = endpoints.OfType<RouteEndpoint>();
if (!routeEndpoints.Any())
{
return null;
}
return matcherEndpoints;
return routeEndpoints;
}
}
}

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNetCore.Routing

View File

@ -3,39 +3,31 @@
using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
namespace Microsoft.AspNetCore.Routing
{
/// <summary>
/// A default implementation of <see cref="IEndpointFeature"/> and <see cref="IRoutingFeature"/>.
/// </summary>
public sealed class EndpointFeature : IEndpointFeature, IRoutingFeature
public sealed class EndpointFeature : IEndpointFeature, IRouteValuesFeature, IRoutingFeature
{
private RouteData _routeData;
private RouteValueDictionary _values;
private RouteValueDictionary _routeValues;
/// <summary>
/// Gets or sets the selected <see cref="Routing.Endpoint"/> for the current
/// Gets or sets the selected <see cref="Http.Endpoint"/> for the current
/// request.
/// </summary>
public Endpoint Endpoint { get; set; }
/// <summary>
/// Gets or sets a delegate that can be used to invoke the current
/// <see cref="Routing.Endpoint"/>.
/// </summary>
public Func<RequestDelegate, RequestDelegate> Invoker { get; set; }
/// <summary>
/// Gets or sets the <see cref="RouteValueDictionary"/> associated with the currrent
/// request.
/// </summary>
public RouteValueDictionary Values
public RouteValueDictionary RouteValues
{
get => _values;
get => _routeValues;
set
{
_values = value;
_routeValues = value;
// RouteData will be created next get with new Values
_routeData = null;
@ -46,7 +38,7 @@ namespace Microsoft.AspNetCore.Routing
/// Gets or sets the <see cref="RouteData"/> for the current request.
/// </summary>
/// <remarks>
/// The setter is not implemented. Use <see cref="Values"/> to set the route values.
/// The setter is not implemented. Use <see cref="RouteValues"/> to set the route values.
/// </remarks>
RouteData IRoutingFeature.RouteData
{
@ -54,7 +46,7 @@ namespace Microsoft.AspNetCore.Routing
{
if (_routeData == null)
{
_routeData = _values == null ? new RouteData() : new RouteData(_values);
_routeData = _routeValues == null ? new RouteData() : new RouteData(_routeValues);
// Note: DataTokens won't update if someone else overwrites the Endpoint
// after route values has been set. This seems find since endpoints are a new
@ -75,4 +67,4 @@ namespace Microsoft.AspNetCore.Routing
set => throw new NotSupportedException();
}
}
}
}

View File

@ -4,6 +4,7 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Routing
@ -40,13 +41,13 @@ namespace Microsoft.AspNetCore.Routing
throw new InvalidOperationException(message);
}
if (feature.Invoker != null)
if (feature.Endpoint?.RequestDelegate != null)
{
Log.ExecutingEndpoint(_logger, feature.Endpoint);
try
{
await feature.Invoker(_next)(httpContext);
await feature.Endpoint.RequestDelegate(httpContext);
}
finally
{

View File

@ -5,6 +5,7 @@ using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing.Matching;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
@ -54,11 +55,10 @@ namespace Microsoft.AspNetCore.Routing
public async Task Invoke(HttpContext httpContext)
{
// For back-compat EndpointRouteValuesFeature implements IEndpointFeature, IRouteValuesFeature and IRoutingFeature
var feature = new EndpointFeature();
httpContext.Features.Set<IEndpointFeature>(feature);
// Back compat support for users of IRoutingFeature
httpContext.Features.Set<IRoutingFeature>(feature);
SetEndpointFeature(httpContext, feature);
// There's an inherent race condition between waiting for init and accessing the matcher
// this is OK because once `_matcher` is initialized, it will not be set to null again.
@ -77,6 +77,18 @@ namespace Microsoft.AspNetCore.Routing
await _next(httpContext);
}
private static void SetEndpointFeature(HttpContext httpContext, EndpointFeature feature)
{
// An IRouteValuesFeature might have already been set
// Copy its RouteValues collection if present
var currentRouteValuesFeature = httpContext.Features.Get<IRouteValuesFeature>();
feature.RouteValues = currentRouteValuesFeature?.RouteValues;
httpContext.Features.Set<IRoutingFeature>(feature);
httpContext.Features.Set<IRouteValuesFeature>(feature);
httpContext.Features.Set<IEndpointFeature>(feature);
}
// Initialization is async to avoid blocking threads while reflection and things
// of that nature take place.
//
@ -127,4 +139,4 @@ namespace Microsoft.AspNetCore.Routing
}
}
}
}
}

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Routing
{

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Routing
{

View File

@ -38,8 +38,7 @@ namespace Microsoft.AspNetCore.Routing.Internal
var endpoints = dataSource.Endpoints;
for (var i = 0; i < endpoints.Count; i++)
{
var endpoint = endpoints[i] as MatcherEndpoint;
if (endpoint != null && endpoint.Metadata.GetMetadata<ISuppressMatchingMetadata>() == null)
if (endpoints[i] is RouteEndpoint endpoint && endpoint.Metadata.GetMetadata<ISuppressMatchingMetadata>() == null)
{
builder.AddEndpoint(endpoint);
}

View File

@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
{
internal readonly struct Candidate
{
public readonly MatcherEndpoint Endpoint;
public readonly RouteEndpoint Endpoint;
// Used to optimize out operations that modify route values.
public readonly CandidateFlags Flags;
@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
public readonly int Score;
// Used in tests.
public Candidate(MatcherEndpoint endpoint)
public Candidate(RouteEndpoint endpoint)
{
Endpoint = endpoint;
@ -63,7 +63,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
}
public Candidate(
MatcherEndpoint endpoint,
RouteEndpoint endpoint,
int score,
KeyValuePair<string, object>[] slots,
(string parameterName, int segmentIndex, int slotIndex)[] captures,

View File

@ -3,6 +3,7 @@
using System;
using System.Runtime.CompilerServices;
using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Routing.Matching
{
@ -35,7 +36,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
/// </summary>
/// <param name="endpoints">The list of endpoints, sorted in descending priority order.</param>
/// <param name="scores">The list of endpoint scores. <see cref="CandidateState.Score"/>.</param>
public CandidateSet(MatcherEndpoint[] endpoints, int[] scores)
public CandidateSet(RouteEndpoint[] endpoints, int[] scores)
{
Count = endpoints.Length;

View File

@ -8,7 +8,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
/// </summary>
public struct CandidateState
{
internal CandidateState(MatcherEndpoint endpoint, int score)
internal CandidateState(RouteEndpoint endpoint, int score)
{
Endpoint = endpoint;
Score = score;
@ -18,12 +18,12 @@ namespace Microsoft.AspNetCore.Routing.Matching
}
/// <summary>
/// Gets the <see cref="Routing.Endpoint"/>.
/// Gets the <see cref="Http.Endpoint"/>.
/// </summary>
public MatcherEndpoint Endpoint { get; }
public RouteEndpoint Endpoint { get; }
/// <summary>
/// Gets the score of the <see cref="Routing.Endpoint"/> within the current
/// Gets the score of the <see cref="Http.Endpoint"/> within the current
/// <see cref="CandidateSet"/>.
/// </summary>
/// <remarks>
@ -40,15 +40,15 @@ namespace Microsoft.AspNetCore.Routing.Matching
public int Score { get; }
/// <summary>
/// Gets or sets a value which indicates where the <see cref="Routing.Endpoint"/> is considered
/// Gets or sets a value which indicates where the <see cref="Http.Endpoint"/> is considered
/// a valid candiate for the current request. Set this value to <c>false</c> to exclude an
/// <see cref="Routing.Endpoint"/> from consideration.
/// <see cref="Http.Endpoint"/> from consideration.
/// </summary>
public bool IsValidCandidate { get; set; }
/// <summary>
/// Gets or sets the <see cref="RouteValueDictionary"/> associated with the
/// <see cref="Routing.Endpoint"/> and the current request.
/// <see cref="Http.Endpoint"/> and the current request.
/// </summary>
public RouteValueDictionary Values { get; set; }
}

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
namespace Microsoft.AspNetCore.Routing.Matching
{
@ -26,7 +27,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
// Used in tests
internal Matcher CurrentMatcher => _cache.Value;
public override Task MatchAsync(HttpContext httpContext, IEndpointFeature feature)
public override Task MatchAsync(HttpContext httpContext, EndpointFeature feature)
{
return CurrentMatcher.MatchAsync(httpContext, feature);
}
@ -36,11 +37,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
var builder = _matcherBuilderFactory();
for (var i = 0; i < endpoints.Count; i++)
{
// By design we only look at MatcherEndpoint here. It's possible to
// By design we only look at RouteEndpoint here. It's possible to
// register other endpoint types, which are non-routable, and it's
// ok that we won't route to them.
var endpoint = endpoints[i] as MatcherEndpoint;
if (endpoint != null && endpoint.Metadata.GetMetadata<ISuppressMatchingMetadata>() == null)
if (endpoints[i] is RouteEndpoint endpoint && endpoint.Metadata.GetMetadata<ISuppressMatchingMetadata>() == null)
{
builder.AddEndpoint(endpoint);
}

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
namespace Microsoft.AspNetCore.Routing.Matching
{
@ -25,7 +26,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
public override Task SelectAsync(
HttpContext httpContext,
IEndpointFeature feature,
EndpointFeature feature,
CandidateSet candidateSet)
{
for (var i = 0; i < _selectorPolicies.Length; i++)
@ -33,7 +34,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
_selectorPolicies[i].Apply(httpContext, candidateSet);
}
MatcherEndpoint endpoint = null;
RouteEndpoint endpoint = null;
RouteValueDictionary values = null;
int? foundScore = null;
for (var i = 0; i < candidateSet.Count; i++)
@ -73,8 +74,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
if (endpoint != null)
{
feature.Endpoint = endpoint;
feature.Invoker = endpoint.Invoker;
feature.Values = values;
feature.RouteValues = values;
}
return Task.CompletedTask;
@ -84,7 +84,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
{
// If we get here it's the result of an ambiguity - we're OK with this
// being a littler slower and more allocatey.
var matches = new List<MatcherEndpoint>();
var matches = new List<RouteEndpoint>();
for (var i = 0; i < candidates.Count; i++)
{
ref var state = ref candidates[i];

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing.Patterns;
namespace Microsoft.AspNetCore.Routing.Matching
@ -22,7 +23,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
_maxSegmentCount = maxSegmentCount;
}
public sealed override Task MatchAsync(HttpContext httpContext, IEndpointFeature feature)
public sealed override Task MatchAsync(HttpContext httpContext, EndpointFeature feature)
{
if (httpContext == null)
{

View File

@ -10,13 +10,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{
internal class DfaMatcherBuilder : MatcherBuilder
{
private readonly List<MatcherEndpoint> _endpoints = new List<MatcherEndpoint>();
private readonly List<RouteEndpoint> _endpoints = new List<RouteEndpoint>();
private readonly ParameterPolicyFactory _parameterPolicyFactory;
private readonly EndpointSelector _selector;
private readonly MatcherPolicy[] _policies;
private readonly INodeBuilderPolicy[] _nodeBuilders;
private readonly MatcherEndpointComparer _comparer;
private readonly RouteEndpointComparer _comparer;
public DfaMatcherBuilder(
ParameterPolicyFactory parameterPolicyFactory,
@ -29,10 +29,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
// Taking care to use _policies, which has been sorted.
_nodeBuilders = _policies.OfType<INodeBuilderPolicy>().ToArray();
_comparer = new MatcherEndpointComparer(_policies.OfType<IEndpointComparerPolicy>().ToArray());
_comparer = new RouteEndpointComparer(_policies.OfType<IEndpointComparerPolicy>().ToArray());
}
public override void AddEndpoint(MatcherEndpoint endpoint)
public override void AddEndpoint(RouteEndpoint endpoint)
{
_endpoints.Add(endpoint);
}
@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
// Since we're doing a BFS we will process each 'level' of the tree in stages
// this list will hold the set of items we need to process at the current
// stage.
var work = new List<(MatcherEndpoint endpoint, List<DfaNode> parents)>();
var work = new List<(RouteEndpoint endpoint, List<DfaNode> parents)>();
var root = new DfaNode() { PathDepth = 0, Label = "/" };
@ -67,7 +67,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
for (var depth = 0; depth <= maxDepth; depth++)
{
// As we process items, collect the next set of items.
var nextWork = new List<(MatcherEndpoint endpoint, List<DfaNode> parents)>();
var nextWork = new List<(RouteEndpoint endpoint, List<DfaNode> parents)>();
for (var i = 0; i < work.Count; i++)
{
@ -192,7 +192,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
return root;
}
private RoutePatternPathSegment GetCurrentSegment(MatcherEndpoint endpoint, int depth)
private RoutePatternPathSegment GetCurrentSegment(RouteEndpoint endpoint, int depth)
{
if (depth < endpoint.RoutePattern.PathSegments.Count)
{
@ -337,7 +337,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
// Builds an array of candidates for a node, assigns a 'score' for each
// endpoint.
internal Candidate[] CreateCandidates(IReadOnlyList<MatcherEndpoint> endpoints)
internal Candidate[] CreateCandidates(IReadOnlyList<RouteEndpoint> endpoints)
{
if (endpoints.Count == 0)
{
@ -367,7 +367,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
}
// internal for tests
internal Candidate CreateCandidate(MatcherEndpoint endpoint, int score)
internal Candidate CreateCandidate(RouteEndpoint endpoint, int score)
{
var assignments = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
var slots = new List<KeyValuePair<string, object>>();
@ -481,7 +481,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
return groups.ToArray();
}
private static bool HasAdditionalRequiredSegments(MatcherEndpoint endpoint, int depth)
private static bool HasAdditionalRequiredSegments(RouteEndpoint endpoint, int depth)
{
for (var i = depth; i < endpoint.RoutePattern.PathSegments.Count; i++)
{
@ -550,7 +550,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
};
// TODO: https://github.com/aspnet/Routing/issues/648
next.Matches.AddRange(edge.Endpoints.Cast<MatcherEndpoint>().ToArray());
next.Matches.AddRange(edge.Endpoints.Cast<RouteEndpoint>().ToArray());
nextWork.Add(next);
parent.PolicyEdges.Add(edge.State, next);

View File

@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
public DfaNode()
{
Literals = new Dictionary<string, DfaNode>(StringComparer.OrdinalIgnoreCase);
Matches = new List<MatcherEndpoint>();
Matches = new List<RouteEndpoint>();
PolicyEdges = new Dictionary<object, DfaNode>();
}
@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
// Just for diagnostics and debugging
public string Label { get; set; }
public List<MatcherEndpoint> Matches { get; }
public List<RouteEndpoint> Matches { get; }
public Dictionary<string, DfaNode> Literals { get; }

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Routing.Matching
{

View File

@ -3,6 +3,7 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
namespace Microsoft.AspNetCore.Routing.Matching
{
@ -21,13 +22,12 @@ namespace Microsoft.AspNetCore.Routing.Matching
/// <param name="candidates">The <see cref="CandidateSet"/>.</param>
/// <returns>A <see cref="Task"/> that completes asynchronously once endpoint selection is complete.</returns>
/// <remarks>
/// An <see cref="EndpointSelector"/> should assign the <see cref="IEndpointFeature.Endpoint"/>,
/// <see cref="IEndpointFeature.Invoker"/>, and <see cref="IEndpointFeature.Values"/> properties
/// once an endpoint is selected.
/// An <see cref="EndpointSelector"/> should assign the <see cref="EndpointFeature.Endpoint"/>
/// and <see cref="EndpointFeature.RouteValues"/> properties once an endpoint is selected.
/// </remarks>
public abstract Task SelectAsync(
HttpContext httpContext,
IEndpointFeature feature,
EndpointFeature feature,
CandidateSet candidates);
}
}

View File

@ -250,8 +250,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
private Endpoint CreateRejectionEndpoint(IEnumerable<string> httpMethods)
{
var allow = string.Join(", ", httpMethods);
return new MatcherEndpoint(
(next) => (context) =>
return new RouteEndpoint(
(context) =>
{
context.Response.StatusCode = 405;
context.Response.Headers.Add("Allow", allow);

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Routing.Matching
{

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Routing.Matching
{

View File

@ -3,6 +3,7 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
namespace Microsoft.AspNetCore.Routing.Matching
{
@ -18,8 +19,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
/// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
/// <param name="feature">
/// The <see cref="IEndpointFeature"/> associated with the current request. The
/// <see cref="IEndpointFeature"/> will be mutated to contain the result of the operation.</param>
/// <see cref="EndpointFeature"/> will be mutated to contain the result of the operation.</param>
/// <returns>A <see cref="Task"/> which represents the asynchronous completion of the operation.</returns>
public abstract Task MatchAsync(HttpContext httpContext, IEndpointFeature feature);
public abstract Task MatchAsync(HttpContext httpContext, EndpointFeature feature);
}
}

View File

@ -5,7 +5,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
{
internal abstract class MatcherBuilder
{
public abstract void AddEndpoint(MatcherEndpoint endpoint);
public abstract void AddEndpoint(RouteEndpoint endpoint);
public abstract Matcher Build();
}

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Routing.Matching
{

View File

@ -6,7 +6,7 @@ using System.Diagnostics;
namespace Microsoft.AspNetCore.Routing.Matching
{
// Use to sort and group MatcherEndpoints.
// Use to sort and group RouteEndpoints.
//
// NOTE:
// When ordering endpoints, we compare the route templates as an absolute last resort.
@ -20,14 +20,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
// IComparer implementation considers the template string as a tiebreaker.
// IEqualityComparer implementation does not.
// This is cool and good.
internal class MatcherEndpointComparer : IComparer<MatcherEndpoint>, IEqualityComparer<MatcherEndpoint>
internal class RouteEndpointComparer : IComparer<RouteEndpoint>, IEqualityComparer<RouteEndpoint>
{
private readonly IComparer<MatcherEndpoint>[] _comparers;
private readonly IComparer<RouteEndpoint>[] _comparers;
public MatcherEndpointComparer(IEndpointComparerPolicy[] policies)
public RouteEndpointComparer(IEndpointComparerPolicy[] policies)
{
// Order, Precedence, (others)...
_comparers = new IComparer<MatcherEndpoint>[2 + policies.Length];
_comparers = new IComparer<RouteEndpoint>[2 + policies.Length];
_comparers[0] = OrderComparer.Instance;
_comparers[1] = PrecedenceComparer.Instance;
for (var i = 0; i < policies.Length; i++)
@ -36,7 +36,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
}
}
public int Compare(MatcherEndpoint x, MatcherEndpoint y)
public int Compare(RouteEndpoint x, RouteEndpoint y)
{
// We don't expose this publicly, and we should never call it on
// a null endpoint.
@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
return compare == 0 ? x.RoutePattern.RawText.CompareTo(y.RoutePattern.RawText) : compare;
}
public bool Equals(MatcherEndpoint x, MatcherEndpoint y)
public bool Equals(RouteEndpoint x, RouteEndpoint y)
{
// We don't expose this publicly, and we should never call it on
// a null endpoint.
@ -59,14 +59,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
return CompareCore(x, y) == 0;
}
public int GetHashCode(MatcherEndpoint obj)
public int GetHashCode(RouteEndpoint obj)
{
// This should not be possible to call publicly.
Debug.Fail("We don't expect this to be called.");
throw new System.NotImplementedException();
}
private int CompareCore(MatcherEndpoint x, MatcherEndpoint y)
private int CompareCore(RouteEndpoint x, RouteEndpoint y)
{
for (var i = 0; i < _comparers.Length; i++)
{
@ -80,21 +80,21 @@ namespace Microsoft.AspNetCore.Routing.Matching
return 0;
}
private class OrderComparer : IComparer<MatcherEndpoint>
private class OrderComparer : IComparer<RouteEndpoint>
{
public static readonly IComparer<MatcherEndpoint> Instance = new OrderComparer();
public static readonly IComparer<RouteEndpoint> Instance = new OrderComparer();
public int Compare(MatcherEndpoint x, MatcherEndpoint y)
public int Compare(RouteEndpoint x, RouteEndpoint y)
{
return x.Order.CompareTo(y.Order);
}
}
private class PrecedenceComparer : IComparer<MatcherEndpoint>
private class PrecedenceComparer : IComparer<RouteEndpoint>
{
public static readonly IComparer<MatcherEndpoint> Instance = new PrecedenceComparer();
public static readonly IComparer<RouteEndpoint> Instance = new PrecedenceComparer();
public int Compare(MatcherEndpoint x, MatcherEndpoint y)
public int Compare(RouteEndpoint x, RouteEndpoint y)
{
return x.RoutePattern.InboundPrecedence.CompareTo(y.RoutePattern.InboundPrecedence);
}

View File

@ -7,39 +7,34 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing.Patterns;
namespace Microsoft.AspNetCore.Routing.Matching
namespace Microsoft.AspNetCore.Routing
{
/// <summary>
/// Represents an <see cref="Endpoint"/> that can be used in URL matching or URL generation.
/// </summary>
public sealed class MatcherEndpoint : Endpoint
public sealed class RouteEndpoint : Endpoint
{
internal static readonly Func<RequestDelegate, RequestDelegate> EmptyInvoker = (next) =>
{
return (context) => Task.CompletedTask;
};
/// <summary>
/// Initializes a new instance of the <see cref="MatcherEndpoint"/> class.
/// Initializes a new instance of the <see cref="RouteEndpoint"/> class.
/// </summary>
/// <param name="invoker">The delegate to invoke to create a <see cref="RequestDelegate"/>.</param>
/// <param name="requestDelegate">The delegate used to process requests for the endpoint.</param>
/// <param name="routePattern">The <see cref="RoutePattern"/> to use in URL matching.</param>
/// <param name="order">The order assigned to the endpoint.</param>
/// <param name="metadata">
/// The <see cref="EndpointMetadataCollection"/> or metadata associated with the endpoint.
/// </param>
/// <param name="displayName">The informational display name of the endpoint.</param>
public MatcherEndpoint(
Func<RequestDelegate, RequestDelegate> invoker,
public RouteEndpoint(
RequestDelegate requestDelegate,
RoutePattern routePattern,
int order,
EndpointMetadataCollection metadata,
string displayName)
: base(metadata, displayName)
: base(requestDelegate, metadata, displayName)
{
if (invoker == null)
if (requestDelegate == null)
{
throw new ArgumentNullException(nameof(invoker));
throw new ArgumentNullException(nameof(requestDelegate));
}
if (routePattern == null)
@ -47,16 +42,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
throw new ArgumentNullException(nameof(routePattern));
}
Invoker = invoker;
RoutePattern = routePattern;
Order = order;
}
/// <summary>
/// Gets the invoker. The invoker is a delegate used to create a <see cref="RequestDelegate"/>.
/// </summary>
public Func<RequestDelegate, RequestDelegate> Invoker { get; }
/// <summary>
/// Gets the order value of endpoint.
/// </summary>

View File

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing.Internal;
using Microsoft.AspNetCore.Routing.Matching;
using Microsoft.AspNetCore.Routing.Template;
@ -56,7 +57,7 @@ namespace Microsoft.AspNetCore.Routing
return matchResults
.Select(matchResult => matchResult.Match)
.Select(match => (MatcherEndpoint)match.Entry.Data);
.Select(match => (RouteEndpoint)match.Entry.Data);
}
private void HandleChange()
@ -103,7 +104,7 @@ namespace Microsoft.AspNetCore.Routing
var namedOutboundMatchResults = new Dictionary<string, List<OutboundMatchResult>>(
StringComparer.OrdinalIgnoreCase);
var endpoints = _endpointDataSource.Endpoints.OfType<MatcherEndpoint>();
var endpoints = _endpointDataSource.Endpoints.OfType<RouteEndpoint>();
foreach (var endpoint in endpoints)
{
// Do not consider an endpoint for link generation if the following marker metadata is on it
@ -135,7 +136,7 @@ namespace Microsoft.AspNetCore.Routing
return (allOutboundMatches, namedOutboundMatchResults);
}
private OutboundRouteEntry CreateOutboundRouteEntry(MatcherEndpoint endpoint)
private OutboundRouteEntry CreateOutboundRouteEntry(RouteEndpoint endpoint)
{
var routeValuesAddressMetadata = endpoint.Metadata.GetMetadata<IRouteValuesAddressMetadata>();
var entry = new OutboundRouteEntry()

View File

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Http;
using Xunit;
namespace Microsoft.AspNetCore.Routing

View File

@ -5,6 +5,7 @@ using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder.Internal;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Internal;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing.Matching;
using Microsoft.AspNetCore.Routing.Patterns;
using Microsoft.AspNetCore.Routing.TestObjects;
@ -146,14 +147,14 @@ namespace Microsoft.AspNetCore.Routing
Assert.False(token.HasChanged);
}
private MatcherEndpoint CreateEndpoint(
private RouteEndpoint CreateEndpoint(
string template,
object defaults = null,
int order = 0,
string routeName = null)
{
return new MatcherEndpoint(
MatcherEndpoint.EmptyInvoker,
return new RouteEndpoint(
TestConstants.EmptyRequestDelegate,
RoutePatternFactory.Parse(template, defaults, parameterPolicies: null),
order,
EndpointMetadataCollection.Empty,

View File

@ -1,10 +1,10 @@
// 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 System;
using System.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Http;
using Xunit;
namespace Microsoft.AspNetCore.Routing
@ -16,8 +16,8 @@ namespace Microsoft.AspNetCore.Routing
{
// Arrange & Act
var dataSource = new DefaultEndpointDataSource(
new TestEndpoint(EndpointMetadataCollection.Empty, "1"),
new TestEndpoint(EndpointMetadataCollection.Empty, "2")
new Endpoint(TestConstants.EmptyRequestDelegate, EndpointMetadataCollection.Empty, "1"),
new Endpoint(TestConstants.EmptyRequestDelegate, EndpointMetadataCollection.Empty, "2")
);
// Assert
@ -32,8 +32,8 @@ namespace Microsoft.AspNetCore.Routing
// Arrange & Act
var dataSource = new DefaultEndpointDataSource(new List<Endpoint>
{
new TestEndpoint(EndpointMetadataCollection.Empty, "1"),
new TestEndpoint(EndpointMetadataCollection.Empty, "2")
new Endpoint(TestConstants.EmptyRequestDelegate, EndpointMetadataCollection.Empty, "1"),
new Endpoint(TestConstants.EmptyRequestDelegate, EndpointMetadataCollection.Empty, "2")
});
// Assert

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing.Constraints;
using Microsoft.AspNetCore.Routing.Internal;
using Microsoft.AspNetCore.Routing.Matching;
@ -25,7 +26,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_Success()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}");
var linkGenerator = CreateLinkGenerator(endpoint);
// Act
@ -40,7 +41,7 @@ namespace Microsoft.AspNetCore.Routing
{
// Arrange
var expectedMessage = "Could not find a matching endpoint to generate a link.";
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
var linkGenerator = CreateLinkGenerator(endpoint);
// Act & Assert
@ -53,7 +54,7 @@ namespace Microsoft.AspNetCore.Routing
public void TryGetLink_Fail()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
var linkGenerator = CreateLinkGenerator(endpoint);
// Act
@ -70,9 +71,9 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_MultipleEndpoints_Success()
{
// Arrange
var endpoint1 = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}/{id?}");
var endpoint2 = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
var endpoint3 = EndpointFactory.CreateMatcherEndpoint("{controller}");
var endpoint1 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id?}");
var endpoint2 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
var endpoint3 = EndpointFactory.CreateRouteEndpoint("{controller}");
var linkGenerator = CreateLinkGenerator(endpoint1, endpoint2, endpoint3);
// Act
@ -86,9 +87,9 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_MultipleEndpoints_Success2()
{
// Arrange
var endpoint1 = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}/{id}");
var endpoint2 = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
var endpoint3 = EndpointFactory.CreateMatcherEndpoint("{controller}");
var endpoint1 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id}");
var endpoint2 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
var endpoint3 = EndpointFactory.CreateRouteEndpoint("{controller}");
var linkGenerator = CreateLinkGenerator(endpoint1, endpoint2, endpoint3);
// Act
@ -102,7 +103,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_EncodesIntermediate_DefaultValues()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("{p1}/{p2=a b}/{p3=foo}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{p1}/{p2=a b}/{p3=foo}");
var linkGenerator = CreateLinkGenerator(endpoint);
// Act
@ -118,7 +119,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_EncodesValue_OfSingleAsteriskCatchAllParameter(string routeValue, string expected)
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}/{*path}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{*path}");
var linkGenerator = CreateLinkGenerator(endpoint);
var httpContext = CreateHttpContext(ambientValues: new { controller = "Home", action = "Index" });
@ -142,7 +143,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_DoesNotEncodeSlashes_OfDoubleAsteriskCatchAllParameter(string routeValue, string expected)
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}/{**path}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{**path}");
var linkGenerator = CreateLinkGenerator(endpoint);
var httpContext = CreateHttpContext(ambientValues: new { controller = "Home", action = "Index" });
@ -157,7 +158,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_EncodesContentOtherThanSlashes_OfDoubleAsteriskCatchAllParameter()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}/{**path}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{**path}");
var linkGenerator = CreateLinkGenerator(endpoint);
var httpContext = CreateHttpContext(ambientValues: new { controller = "Home", action = "Index" });
@ -172,7 +173,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_EncodesValues()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
var linkGenerator = CreateLinkGenerator(endpoint);
var httpContext = CreateHttpContext(ambientValues: new { controller = "Home", action = "Index" });
@ -187,7 +188,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_ForListOfStrings()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
var linkGenerator = CreateLinkGenerator(endpoint);
var context = CreateHttpContext(ambientValues: new { controller = "Home", action = "Index" });
@ -202,7 +203,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_ForListOfInts()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
var linkGenerator = CreateLinkGenerator(endpoint);
var httpContext = CreateHttpContext(ambientValues: new { controller = "Home", action = "Index" });
@ -217,7 +218,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_ForList_Empty()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
var linkGenerator = CreateLinkGenerator(endpoint);
var httpContext = CreateHttpContext(ambientValues: new { controller = "Home", action = "Index" });
@ -232,7 +233,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_ForList_StringWorkaround()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
var linkGenerator = CreateLinkGenerator(endpoint);
var httpContext = CreateHttpContext(ambientValues: new { controller = "Home", action = "Index" });
@ -249,7 +250,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_Success_AmbientValues()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
var linkGenerator = CreateLinkGenerator(endpoint);
var httpContext = CreateHttpContext(ambientValues: new { controller = "Home" });
@ -264,7 +265,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_GeneratesLowercaseUrl_SetOnRouteOptions()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
var linkGenerator = CreateLinkGenerator(new[] { endpoint }, new RouteOptions() { LowercaseUrls = true });
var httpContext = CreateHttpContext(ambientValues: new { controller = "Home" });
@ -279,7 +280,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_GeneratesLowercaseQueryString_SetOnRouteOptions()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
var linkGenerator = CreateLinkGenerator(
new[] { endpoint },
new RouteOptions() { LowercaseUrls = true, LowercaseQueryStrings = true });
@ -298,7 +299,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_GeneratesLowercaseQueryString_OnlyIfLowercaseUrlIsTrue_SetOnRouteOptions()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
var linkGenerator = CreateLinkGenerator(
new[] { endpoint },
new RouteOptions() { LowercaseUrls = false, LowercaseQueryStrings = true });
@ -317,7 +318,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_AppendsTrailingSlash_SetOnRouteOptions()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
var linkGenerator = CreateLinkGenerator(
new[] { endpoint },
new RouteOptions() { AppendTrailingSlash = true });
@ -334,7 +335,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_GeneratesLowercaseQueryStringAndTrailingSlash_SetOnRouteOptions()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
var linkGenerator = CreateLinkGenerator(
new[] { endpoint },
new RouteOptions() { LowercaseUrls = true, LowercaseQueryStrings = true, AppendTrailingSlash = true });
@ -353,7 +354,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_LowercaseUrlSetToTrue_OnRouteOptions_OverridenByCallsiteValue()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
var linkGenerator = CreateLinkGenerator(
new[] { endpoint },
new RouteOptions() { LowercaseUrls = true });
@ -376,7 +377,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_LowercaseUrlSetToFalse_OnRouteOptions_OverridenByCallsiteValue()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
var linkGenerator = CreateLinkGenerator(
new[] { endpoint },
new RouteOptions() { LowercaseUrls = false });
@ -399,7 +400,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_LowercaseUrlQueryStringsSetToTrue_OnRouteOptions_OverridenByCallsiteValue()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
var linkGenerator = CreateLinkGenerator(
new[] { endpoint },
new RouteOptions() { LowercaseUrls = true, LowercaseQueryStrings = true });
@ -423,7 +424,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_LowercaseUrlQueryStringsSetToFalse_OnRouteOptions_OverridenByCallsiteValue()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
var linkGenerator = CreateLinkGenerator(
new[] { endpoint },
new RouteOptions() { LowercaseUrls = false, LowercaseQueryStrings = false });
@ -447,7 +448,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_AppendTrailingSlashSetToFalse_OnRouteOptions_OverridenByCallsiteValue()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
var linkGenerator = CreateLinkGenerator(
new[] { endpoint },
new RouteOptions() { AppendTrailingSlash = false });
@ -470,7 +471,7 @@ namespace Microsoft.AspNetCore.Routing
public void RouteGenerationRejectsConstraints()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint(
var endpoint = EndpointFactory.CreateRouteEndpoint(
"{p1}/{p2}",
defaults: new { p2 = "catchall" },
constraints: new { p2 = "\\d{4}" });
@ -491,7 +492,7 @@ namespace Microsoft.AspNetCore.Routing
public void RouteGenerationAcceptsConstraints()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint(
var endpoint = EndpointFactory.CreateRouteEndpoint(
"{p1}/{p2}",
defaults: new { p2 = "catchall" },
constraints: new { p2 = new RegexRouteConstraint("\\d{4}"), });
@ -513,7 +514,7 @@ namespace Microsoft.AspNetCore.Routing
public void RouteWithCatchAllRejectsConstraints()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint(
var endpoint = EndpointFactory.CreateRouteEndpoint(
"{p1}/{*p2}",
defaults: new { p2 = "catchall" },
constraints: new { p2 = new RegexRouteConstraint("\\d{4}") });
@ -534,7 +535,7 @@ namespace Microsoft.AspNetCore.Routing
public void RouteWithCatchAllAcceptsConstraints()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint(
var endpoint = EndpointFactory.CreateRouteEndpoint(
"{p1}/{*p2}",
defaults: new { p2 = "catchall" },
constraints: new { p2 = new RegexRouteConstraint("\\d{4}") });
@ -567,7 +568,7 @@ namespace Microsoft.AspNetCore.Routing
It.IsAny<RouteDirection>()))
.Returns(true)
.Verifiable();
var endpoint = EndpointFactory.CreateMatcherEndpoint(
var endpoint = EndpointFactory.CreateRouteEndpoint(
"{p1}/{p2}",
defaults: new { p2 = "catchall" },
constraints: new { p2 = target.Object });
@ -593,7 +594,7 @@ namespace Microsoft.AspNetCore.Routing
{
// Arrange
var constraint = new CapturingConstraint();
var endpoint = EndpointFactory.CreateMatcherEndpoint(
var endpoint = EndpointFactory.CreateRouteEndpoint(
template: "slug/Home/Store",
defaults: new { controller = "Home", action = "Store" },
constraints: new { c = constraint });
@ -622,7 +623,7 @@ namespace Microsoft.AspNetCore.Routing
{
// Arrange
var constraint = new CapturingConstraint();
var endpoint = EndpointFactory.CreateMatcherEndpoint(
var endpoint = EndpointFactory.CreateRouteEndpoint(
template: "slug/Home/Store",
defaults: new { controller = "Home", action = "Store", otherthing = "17" },
constraints: new { c = constraint });
@ -645,7 +646,7 @@ namespace Microsoft.AspNetCore.Routing
{
// Arrange
var constraint = new CapturingConstraint();
var endpoint = EndpointFactory.CreateMatcherEndpoint(
var endpoint = EndpointFactory.CreateRouteEndpoint(
template: "slug/{controller}/{action}",
defaults: new { action = "Index" },
constraints: new { c = constraint, });
@ -669,7 +670,7 @@ namespace Microsoft.AspNetCore.Routing
{
// Arrange
var constraint = new CapturingConstraint();
var endpoint = EndpointFactory.CreateMatcherEndpoint(
var endpoint = EndpointFactory.CreateRouteEndpoint(
template: "slug/Home/Store",
defaults: new { controller = "Home", action = "Store", otherthing = "17", thirdthing = "13" },
constraints: new { c = constraint, });
@ -694,7 +695,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_InlineConstraints_Success()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint(
var endpoint = EndpointFactory.CreateRouteEndpoint(
template: "Home/Index/{id:int}",
defaults: new { controller = "Home", action = "Index" },
constraints: new { });
@ -714,7 +715,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_InlineConstraints_NonMatchingvalue()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint(
var endpoint = EndpointFactory.CreateRouteEndpoint(
template: "Home/Index/{id}",
defaults: new { controller = "Home", action = "Index" },
constraints: new { id = "int" });
@ -735,7 +736,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_InlineConstraints_OptionalParameter_ValuePresent()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint(
var endpoint = EndpointFactory.CreateRouteEndpoint(
template: "Home/Index/{id:int?}",
defaults: new { controller = "Home", action = "Index" },
constraints: new { });
@ -753,7 +754,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_InlineConstraints_OptionalParameter_ValueNotPresent()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint(
var endpoint = EndpointFactory.CreateRouteEndpoint(
template: "Home/Index/{id?}",
defaults: new { controller = "Home", action = "Index" },
constraints: new { id = "int" });
@ -771,7 +772,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_InlineConstraints_OptionalParameter_ValuePresent_ConstraintFails()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint(
var endpoint = EndpointFactory.CreateRouteEndpoint(
template: "Home/Index/{id?}",
defaults: new { controller = "Home", action = "Index" },
constraints: new { id = "int" });
@ -792,7 +793,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_InlineConstraints_MultipleInlineConstraints()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint(
var endpoint = EndpointFactory.CreateRouteEndpoint(
template: "Home/Index/{id:int:range(1,20)}",
defaults: new { controller = "Home", action = "Index" },
constraints: new { });
@ -812,7 +813,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_InlineConstraints_CompositeInlineConstraint_Fails()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint(
var endpoint = EndpointFactory.CreateRouteEndpoint(
template: "Home/Index/{id:int:range(1,20)}",
defaults: new { controller = "Home", action = "Index" },
constraints: new { });
@ -834,7 +835,7 @@ namespace Microsoft.AspNetCore.Routing
{
// Arrange
var constraint = new MaxLengthRouteConstraint(20);
var endpoint = EndpointFactory.CreateMatcherEndpoint(
var endpoint = EndpointFactory.CreateRouteEndpoint(
template: "Home/Index/{name}",
defaults: new { controller = "Home", action = "Index" },
constraints: new { name = constraint });
@ -854,7 +855,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_OptionalParameter_ParameterPresentInValues()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}/{name?}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{name?}");
var linkGenerator = CreateLinkGenerator(endpoint);
var httpContext = CreateHttpContext(ambientValues: new { });
@ -871,7 +872,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_OptionalParameter_ParameterNotPresentInValues()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}/{name?}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{name?}");
var linkGenerator = CreateLinkGenerator(endpoint);
var httpContext = CreateHttpContext(ambientValues: new { });
@ -888,7 +889,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_OptionalParameter_ParameterPresentInValuesAndDefaults()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint(
var endpoint = EndpointFactory.CreateRouteEndpoint(
template: "{controller}/{action}/{name}",
defaults: new { name = "default-products" });
var linkGenerator = CreateLinkGenerator(endpoint);
@ -907,7 +908,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_OptionalParameter_ParameterNotPresentInValues_PresentInDefaults()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint(
var endpoint = EndpointFactory.CreateRouteEndpoint(
template: "{controller}/{action}/{name}",
defaults: new { name = "products" });
var linkGenerator = CreateLinkGenerator(endpoint);
@ -926,7 +927,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_ParameterNotPresentInTemplate_PresentInValues()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}/{name}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{name}");
var linkGenerator = CreateLinkGenerator(endpoint);
var httpContext = CreateHttpContext(ambientValues: new { });
@ -943,7 +944,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_OptionalParameter_FollowedByDotAfterSlash_ParameterPresent()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint(
var endpoint = EndpointFactory.CreateRouteEndpoint(
template: "{controller}/{action}/.{name?}");
var linkGenerator = CreateLinkGenerator(endpoint);
var httpContext = CreateHttpContext(ambientValues: new { });
@ -961,7 +962,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_OptionalParameter_FollowedByDotAfterSlash_ParameterNotPresent()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}/.{name?}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/.{name?}");
var linkGenerator = CreateLinkGenerator(endpoint);
var httpContext = CreateHttpContext(ambientValues: new { });
@ -976,7 +977,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_OptionalParameter_InSimpleSegment()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}/{name?}");
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{name?}");
var linkGenerator = CreateLinkGenerator(endpoint);
var httpContext = CreateHttpContext(ambientValues: new { });
@ -991,7 +992,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_TwoOptionalParameters_OneValueFromAmbientValues()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("a/{b=15}/{c?}/{d?}");
var endpoint = EndpointFactory.CreateRouteEndpoint("a/{b=15}/{c?}/{d?}");
var linkGenerator = CreateLinkGenerator(endpoint);
var httpContext = CreateHttpContext(ambientValues: new { c = "17" });
@ -1006,7 +1007,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_OptionalParameterAfterDefault_OneValueFromAmbientValues()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("a/{b=15}/{c?}");
var endpoint = EndpointFactory.CreateRouteEndpoint("a/{b=15}/{c?}");
var linkGenerator = CreateLinkGenerator(endpoint);
var httpContext = CreateHttpContext(ambientValues: new { c = "17" });
@ -1021,7 +1022,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetLink_TwoOptionalParametersAfterDefault_LastValueFromAmbientValues()
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint("a/{b=15}/{c?}/{d?}");
var endpoint = EndpointFactory.CreateRouteEndpoint("a/{b=15}/{c?}/{d?}");
var linkGenerator = CreateLinkGenerator(endpoint);
var httpContext = CreateHttpContext(ambientValues: new { d = "17" });
@ -1114,7 +1115,7 @@ namespace Microsoft.AspNetCore.Routing
object defaults)
{
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint(
var endpoint = EndpointFactory.CreateRouteEndpoint(
"Products/Edit/{id}",
requiredValues: requiredValues,
defaults: defaults);
@ -1138,7 +1139,7 @@ namespace Microsoft.AspNetCore.Routing
// Verifying that discarding works in general usage case i.e when keys are not like controller, action etc.
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint(
var endpoint = EndpointFactory.CreateRouteEndpoint(
"Products/Edit/{id}",
requiredValues: new { c = "Products", a = "Edit" },
defaults: new { c = "Products", a = "Edit" });
@ -1162,7 +1163,7 @@ namespace Microsoft.AspNetCore.Routing
// Verifying that discarding works in general usage case i.e when keys are not like controller, action etc.
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint(
var endpoint = EndpointFactory.CreateRouteEndpoint(
"Products/Edit/{id}",
requiredValues: new { c = "Products", a = "Edit" },
defaults: new { c = "Products", a = "Edit" });
@ -1268,7 +1269,7 @@ namespace Microsoft.AspNetCore.Routing
// Linking to a different action on the same controller
// Arrange
var endpoint = EndpointFactory.CreateMatcherEndpoint(
var endpoint = EndpointFactory.CreateRouteEndpoint(
"Products/Edit/{id}",
requiredValues: requiredValues,
defaults: defaults);
@ -1293,11 +1294,11 @@ namespace Microsoft.AspNetCore.Routing
var services = GetBasicServices();
services.TryAddEnumerable(
ServiceDescriptor.Singleton<IEndpointFinder<INameMetadata>, EndpointFinderByName>());
var endpoint1 = EndpointFactory.CreateMatcherEndpoint(
var endpoint1 = EndpointFactory.CreateRouteEndpoint(
"Products/Details/{id}",
requiredValues: new { controller = "Products", action = "Details" },
defaults: new { controller = "Products", action = "Details" });
var endpoint2 = EndpointFactory.CreateMatcherEndpoint(
var endpoint2 = EndpointFactory.CreateRouteEndpoint(
"Customers/Details/{id}",
requiredValues: new { controller = "Customers", action = "Details" },
defaults: new { controller = "Customers", action = "Details" },
@ -1324,11 +1325,11 @@ namespace Microsoft.AspNetCore.Routing
var services = GetBasicServices();
services.TryAddEnumerable(
ServiceDescriptor.Singleton<IEndpointFinder<INameMetadata>, EndpointFinderByName>());
var endpoint1 = EndpointFactory.CreateMatcherEndpoint(
var endpoint1 = EndpointFactory.CreateRouteEndpoint(
"Products/Details/{id}",
requiredValues: new { controller = "Products", action = "Details" },
defaults: new { controller = "Products", action = "Details" });
var endpoint2 = EndpointFactory.CreateMatcherEndpoint(
var endpoint2 = EndpointFactory.CreateRouteEndpoint(
"Customers/Details/{id}",
requiredValues: new { controller = "Customers", action = "Details" },
defaults: new { controller = "Customers", action = "Details" },
@ -1356,7 +1357,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetTemplate_ByRouteValues_ReturnsTemplate()
{
// Arrange
var endpoint1 = EndpointFactory.CreateMatcherEndpoint(
var endpoint1 = EndpointFactory.CreateRouteEndpoint(
"Product/Edit/{id}",
requiredValues: new { controller = "Product", action = "Edit", area = (string)null, page = (string)null },
defaults: new { controller = "Product", action = "Edit", area = (string)null, page = (string)null });
@ -1379,7 +1380,7 @@ namespace Microsoft.AspNetCore.Routing
public void GetTemplate_ByRouteName_ReturnsTemplate()
{
// Arrange
var endpoint1 = EndpointFactory.CreateMatcherEndpoint(
var endpoint1 = EndpointFactory.CreateRouteEndpoint(
"Product/Edit/{id}",
defaults: new { controller = "Product", action = "Edit", area = (string)null, page = (string)null },
metadata: new RouteValuesAddressMetadata(
@ -1403,13 +1404,13 @@ namespace Microsoft.AspNetCore.Routing
public void GetTemplate_ByRouteName_ReturnsTemplate_WithMultipleEndpoints()
{
// Arrange
var endpoint1 = EndpointFactory.CreateMatcherEndpoint(
var endpoint1 = EndpointFactory.CreateRouteEndpoint(
"Product/Edit/{id}",
defaults: new { controller = "Product", action = "Edit", area = (string)null, page = (string)null },
metadata: new RouteValuesAddressMetadata(
"default",
new RouteValueDictionary(new { controller = "Product", action = "Edit", area = (string)null, page = (string)null })));
var endpoint2 = EndpointFactory.CreateMatcherEndpoint(
var endpoint2 = EndpointFactory.CreateRouteEndpoint(
"Product/Details/{id}",
defaults: new { controller = "Product", action = "Edit", area = (string)null, page = (string)null },
metadata: new RouteValuesAddressMetadata(
@ -1436,11 +1437,11 @@ namespace Microsoft.AspNetCore.Routing
var services = GetBasicServices();
services.TryAddEnumerable(
ServiceDescriptor.Singleton<IEndpointFinder<INameMetadata>, EndpointFinderByName>());
var endpoint1 = EndpointFactory.CreateMatcherEndpoint(
var endpoint1 = EndpointFactory.CreateRouteEndpoint(
"Product/Edit/{id}",
requiredValues: new { controller = "Product", action = "Edit", area = (string)null, page = (string)null },
defaults: new { controller = "Product", action = "Edit", area = (string)null, page = (string)null });
var endpoint2 = EndpointFactory.CreateMatcherEndpoint(
var endpoint2 = EndpointFactory.CreateRouteEndpoint(
"Customers/Details/{id}",
requiredValues: new { controller = "Customers", action = "Details" },
defaults: new { controller = "Customers", action = "Details" },
@ -1466,11 +1467,11 @@ namespace Microsoft.AspNetCore.Routing
var services = GetBasicServices();
services.TryAddEnumerable(
ServiceDescriptor.Singleton<IEndpointFinder<INameMetadata>, EndpointFinderByName>());
var endpoint1 = EndpointFactory.CreateMatcherEndpoint(
var endpoint1 = EndpointFactory.CreateRouteEndpoint(
"Product/Edit/{id}",
requiredValues: new { controller = "Product", action = "Edit", area = (string)null, page = (string)null },
defaults: new { controller = "Product", action = "Edit", area = (string)null, page = (string)null });
var endpoint2 = EndpointFactory.CreateMatcherEndpoint(
var endpoint2 = EndpointFactory.CreateRouteEndpoint(
"Customers/Details/{id}",
requiredValues: new { controller = "Customers", action = "Details" },
defaults: new { controller = "Customers", action = "Details" },
@ -1500,7 +1501,7 @@ namespace Microsoft.AspNetCore.Routing
public void MakeUrl_GeneratesLink_WithExtraRouteValues()
{
// Arrange
var endpoint1 = EndpointFactory.CreateMatcherEndpoint(
var endpoint1 = EndpointFactory.CreateRouteEndpoint(
"Product/Edit/{id}",
requiredValues: new { controller = "Product", action = "Edit", area = (string)null, page = (string)null },
defaults: new { controller = "Product", action = "Edit", area = (string)null, page = (string)null });
@ -1564,10 +1565,13 @@ namespace Microsoft.AspNetCore.Routing
private HttpContext CreateHttpContext(object ambientValues)
{
var httpContext = new DefaultHttpContext();
httpContext.Features.Set<IEndpointFeature>(new EndpointFeature
var feature = new EndpointFeature
{
Values = new RouteValueDictionary(ambientValues)
});
RouteValues = new RouteValueDictionary(ambientValues)
};
httpContext.Features.Set<IEndpointFeature>(feature);
httpContext.Features.Set<IRouteValuesFeature>(feature);
return httpContext;
}

View File

@ -1,7 +1,7 @@
// 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.Matching;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing.Patterns;
using System;
using System.Collections.Generic;
@ -10,7 +10,7 @@ namespace Microsoft.AspNetCore.Routing
{
internal static class EndpointFactory
{
public static MatcherEndpoint CreateMatcherEndpoint(
public static RouteEndpoint CreateRouteEndpoint(
string template,
object defaults = null,
object constraints = null,
@ -25,8 +25,8 @@ namespace Microsoft.AspNetCore.Routing
d.Add(new RouteValuesAddressMetadata(null, new RouteValueDictionary(requiredValues)));
}
return new MatcherEndpoint(
MatcherEndpoint.EmptyInvoker,
return new RouteEndpoint(
TestConstants.EmptyRequestDelegate,
RoutePatternFactory.Parse(template, defaults, constraints),
order,
new EndpointMetadataCollection(d),

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing.Matching;
using Microsoft.AspNetCore.Routing.Patterns;
using Xunit;
@ -18,8 +19,8 @@ namespace Microsoft.AspNetCore.Routing
var feature = new EndpointFeature()
{
Endpoint = new MatcherEndpoint(
MatcherEndpoint.EmptyInvoker,
Endpoint = new RouteEndpoint(
TestConstants.EmptyRequestDelegate,
RoutePatternFactory.Parse("/"),
0,
new EndpointMetadataCollection(new DataTokensMetadata(expected)),
@ -40,8 +41,8 @@ namespace Microsoft.AspNetCore.Routing
// Arrange
var feature = new EndpointFeature()
{
Endpoint = new MatcherEndpoint(
MatcherEndpoint.EmptyInvoker,
Endpoint = new RouteEndpoint(
TestConstants.EmptyRequestDelegate,
RoutePatternFactory.Parse("/"),
0,
new EndpointMetadataCollection(),

View File

@ -4,6 +4,7 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing.TestObjects;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
@ -19,8 +20,7 @@ namespace Microsoft.AspNetCore.Routing
public async Task Invoke_OnCall_SetsEndpointFeature()
{
// Arrange
var httpContext = new DefaultHttpContext();
httpContext.RequestServices = new TestServiceProvider();
var httpContext = CreateHttpContext();
var middleware = CreateMiddleware();
@ -43,8 +43,7 @@ namespace Microsoft.AspNetCore.Routing
TestSink.EnableWithTypeName<EndpointRoutingMiddleware>);
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
var httpContext = new DefaultHttpContext();
httpContext.RequestServices = new TestServiceProvider();
var httpContext = CreateHttpContext();
var logger = new Logger<EndpointRoutingMiddleware>(loggerFactory);
var middleware = CreateMiddleware(logger);
@ -62,8 +61,7 @@ namespace Microsoft.AspNetCore.Routing
public async Task Invoke_BackCompatGetRouteValue_ValueUsedFromEndpointFeature()
{
// Arrange
var httpContext = new DefaultHttpContext();
httpContext.RequestServices = new TestServiceProvider();
var httpContext = CreateHttpContext();
var middleware = CreateMiddleware();
@ -71,7 +69,7 @@ namespace Microsoft.AspNetCore.Routing
await middleware.Invoke(httpContext);
var routeData = httpContext.GetRouteData();
var routeValue = httpContext.GetRouteValue("controller");
var endpointFeature = httpContext.Features.Get<IEndpointFeature>();
var routeValuesFeature = httpContext.Features.Get<IRouteValuesFeature>();
// Assert
Assert.NotNull(routeData);
@ -79,15 +77,14 @@ namespace Microsoft.AspNetCore.Routing
// changing route data value is reflected in endpoint feature values
routeData.Values["testKey"] = "testValue";
Assert.Equal("testValue", endpointFeature.Values["testKey"]);
Assert.Equal("testValue", routeValuesFeature.RouteValues["testKey"]);
}
[Fact]
public async Task Invoke_BackCompatGetDataTokens_ValueUsedFromEndpointMetadata()
{
// Arrange
var httpContext = new DefaultHttpContext();
httpContext.RequestServices = new TestServiceProvider();
var httpContext = CreateHttpContext();
var middleware = CreateMiddleware();
@ -95,7 +92,7 @@ namespace Microsoft.AspNetCore.Routing
await middleware.Invoke(httpContext);
var routeData = httpContext.GetRouteData();
var routeValue = httpContext.GetRouteValue("controller");
var endpointFeature = httpContext.Features.Get<IEndpointFeature>();
var routeValuesFeature = httpContext.Features.Get<IRouteValuesFeature>();
// Assert
Assert.NotNull(routeData);
@ -103,7 +100,20 @@ namespace Microsoft.AspNetCore.Routing
// changing route data value is reflected in endpoint feature values
routeData.Values["testKey"] = "testValue";
Assert.Equal("testValue", endpointFeature.Values["testKey"]);
Assert.Equal("testValue", routeValuesFeature.RouteValues["testKey"]);
}
private HttpContext CreateHttpContext()
{
var feature = new EndpointFeature();
var httpContext = new DefaultHttpContext();
httpContext.Features.Set<IEndpointFeature>(feature);
httpContext.Features.Set<IRouteValuesFeature>(feature);
httpContext.RequestServices = new TestServiceProvider();
return httpContext;
}
private EndpointRoutingMiddleware CreateMiddleware(Logger<EndpointRoutingMiddleware> logger = null)

View File

@ -4,6 +4,7 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
namespace Microsoft.AspNetCore.Routing.Matching
{
@ -19,7 +20,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
Matchers = matchers;
}
public override Task MatchAsync(HttpContext httpContext, IEndpointFeature feature)
public override Task MatchAsync(HttpContext httpContext, EndpointFeature feature)
{
if (httpContext == null)
{
@ -37,7 +38,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
if (Matchers[i].TryMatch(path))
{
feature.Endpoint = Matchers[i].Endpoint;
feature.Values = new RouteValueDictionary();
feature.RouteValues = new RouteValueDictionary();
}
}
@ -46,12 +47,12 @@ namespace Microsoft.AspNetCore.Routing.Matching
public sealed class InnerMatcher : Matcher
{
public readonly MatcherEndpoint Endpoint;
public readonly RouteEndpoint Endpoint;
private readonly string[] _segments;
private readonly Candidate[] _candidates;
public InnerMatcher(string[] segments, MatcherEndpoint endpoint)
public InnerMatcher(string[] segments, RouteEndpoint endpoint)
{
_segments = segments;
Endpoint = endpoint;
@ -120,12 +121,12 @@ namespace Microsoft.AspNetCore.Routing.Matching
return Array.Empty<Candidate>();
}
public override Task MatchAsync(HttpContext httpContext, IEndpointFeature feature)
public override Task MatchAsync(HttpContext httpContext, EndpointFeature feature)
{
if (TryMatch(httpContext.Request.Path.Value))
{
feature.Endpoint = Endpoint;
feature.Values = new RouteValueDictionary();
feature.RouteValues = new RouteValueDictionary();
}
return Task.CompletedTask;

View File

@ -11,9 +11,9 @@ namespace Microsoft.AspNetCore.Routing.Matching
{
internal class BarebonesMatcherBuilder : MatcherBuilder
{
private List<MatcherEndpoint> _endpoints = new List<MatcherEndpoint>();
private List<RouteEndpoint> _endpoints = new List<RouteEndpoint>();
public override void AddEndpoint(MatcherEndpoint endpoint)
public override void AddEndpoint(RouteEndpoint endpoint)
{
_endpoints.Add(endpoint);
}

View File

@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
return Task.CompletedTask;
}
internal override Matcher CreateMatcher(params MatcherEndpoint[] endpoints)
internal override Matcher CreateMatcher(params RouteEndpoint[] endpoints)
{
var builder = new BarebonesMatcherBuilder();
for (int i = 0; i < endpoints.Length; i++)

View File

@ -3,6 +3,7 @@
using System;
using System.Linq;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing.Patterns;
using Moq;
using Xunit;
@ -24,7 +25,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
public void Create_CreatesCandidateSet(int count)
{
// Arrange
var endpoints = new MatcherEndpoint[count];
var endpoints = new RouteEndpoint[count];
for (var i = 0; i < endpoints.Length; i++)
{
endpoints[i] = CreateEndpoint($"/{i}");
@ -60,7 +61,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
public void Create_CreatesCandidateSet_TestConstructor(int count)
{
// Arrange
var endpoints = new MatcherEndpoint[count];
var endpoints = new RouteEndpoint[count];
for (var i = 0; i < endpoints.Length; i++)
{
endpoints[i] = CreateEndpoint($"/{i}");
@ -80,10 +81,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
}
}
private MatcherEndpoint CreateEndpoint(string template)
private RouteEndpoint CreateEndpoint(string template)
{
return new MatcherEndpoint(
MatcherEndpoint.EmptyInvoker,
return new RouteEndpoint(
TestConstants.EmptyRequestDelegate,
RoutePatternFactory.Parse(template),
0,
EndpointMetadataCollection.Empty,

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing.Patterns;
using Microsoft.AspNetCore.Routing.TestObjects;
using Xunit;
@ -34,8 +35,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
var dataSource = new DynamicEndpointDataSource();
var matcher = new DataSourceDependentMatcher(dataSource, TestMatcherBuilder.Create);
var endpoint = new MatcherEndpoint(
MatcherEndpoint.EmptyInvoker,
var endpoint = new RouteEndpoint(
TestConstants.EmptyRequestDelegate,
RoutePatternFactory.Parse("a/b/c"),
0,
EndpointMetadataCollection.Empty,
@ -52,11 +53,11 @@ namespace Microsoft.AspNetCore.Routing.Matching
}
[Fact]
public void Matcher_Ignores_NonMatcherEndpoint()
public void Matcher_Ignores_NonRouteEndpoint()
{
// Arrange
var dataSource = new DynamicEndpointDataSource();
var endpoint = new TestEndpoint(EndpointMetadataCollection.Empty, "test");
var endpoint = new Endpoint(TestConstants.EmptyRequestDelegate, EndpointMetadataCollection.Empty, "test");
dataSource.AddEndpoint(endpoint);
// Act
@ -72,8 +73,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
{
// Arrange
var dataSource = new DynamicEndpointDataSource();
var endpoint = new MatcherEndpoint(
MatcherEndpoint.EmptyInvoker,
var endpoint = new RouteEndpoint(
TestConstants.EmptyRequestDelegate,
RoutePatternFactory.Parse("/"),
0,
new EndpointMetadataCollection(new SuppressMatchingMetadata()),
@ -116,9 +117,9 @@ namespace Microsoft.AspNetCore.Routing.Matching
{
public static Func<MatcherBuilder> Create = () => new TestMatcherBuilder();
private List<MatcherEndpoint> Endpoints { get; } = new List<MatcherEndpoint>();
private List<RouteEndpoint> Endpoints { get; } = new List<RouteEndpoint>();
public override void AddEndpoint(MatcherEndpoint endpoint)
public override void AddEndpoint(RouteEndpoint endpoint)
{
Endpoints.Add(endpoint);
}
@ -131,9 +132,9 @@ namespace Microsoft.AspNetCore.Routing.Matching
private class TestMatcher : Matcher
{
public IReadOnlyList<MatcherEndpoint> Endpoints { get; set; }
public IReadOnlyList<RouteEndpoint> Endpoints { get; set; }
public override Task MatchAsync(HttpContext httpContext, IEndpointFeature feature)
public override Task MatchAsync(HttpContext httpContext, EndpointFeature feature)
{
throw new NotImplementedException();
}

View File

@ -3,6 +3,7 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing.Patterns;
using Moq;
using Xunit;
@ -15,7 +16,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
public async Task SelectAsync_NoCandidates_DoesNothing()
{
// Arrange
var endpoints = new MatcherEndpoint[] { };
var endpoints = new RouteEndpoint[] { };
var scores = new int[] { };
var candidateSet = CreateCandidateSet(endpoints, scores);
@ -33,7 +34,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
public async Task SelectAsync_NoValidCandidates_DoesNothing()
{
// Arrange
var endpoints = new MatcherEndpoint[] { CreateEndpoint("/test"), };
var endpoints = new RouteEndpoint[] { CreateEndpoint("/test"), };
var scores = new int[] { 0, };
var candidateSet = CreateCandidateSet(endpoints, scores);
@ -48,14 +49,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
// Assert
Assert.Null(feature.Endpoint);
Assert.Null(feature.Values);
}
[Fact]
public async Task SelectAsync_SingleCandidate_ChoosesCandidate()
{
// Arrange
var endpoints = new MatcherEndpoint[] { CreateEndpoint("/test"), };
var endpoints = new RouteEndpoint[] { CreateEndpoint("/test"), };
var scores = new int[] { 0, };
var candidateSet = CreateCandidateSet(endpoints, scores);
@ -70,18 +70,16 @@ namespace Microsoft.AspNetCore.Routing.Matching
// Assert
Assert.Same(endpoints[0], feature.Endpoint);
Assert.Same(endpoints[0].Invoker, feature.Invoker);
Assert.NotNull(feature.Values);
}
[Fact]
public async Task SelectAsync_SingleValidCandidate_ChoosesCandidate()
{
// Arrange
var endpoints = new MatcherEndpoint[] { CreateEndpoint("/test1"), CreateEndpoint("/test2"), };
var endpoints = new RouteEndpoint[] { CreateEndpoint("/test1"), CreateEndpoint("/test2"), };
var scores = new int[] { 0, 0 };
var candidateSet = CreateCandidateSet(endpoints, scores);
candidateSet[0].IsValidCandidate = false;
candidateSet[1].IsValidCandidate = true;
@ -99,7 +97,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
public async Task SelectAsync_SingleValidCandidateInGroup_ChoosesCandidate()
{
// Arrange
var endpoints = new MatcherEndpoint[] { CreateEndpoint("/test1"), CreateEndpoint("/test2"), CreateEndpoint("/test3"), };
var endpoints = new RouteEndpoint[] { CreateEndpoint("/test1"), CreateEndpoint("/test2"), CreateEndpoint("/test3"), };
var scores = new int[] { 0, 0, 1 };
var candidateSet = CreateCandidateSet(endpoints, scores);
@ -121,7 +119,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
public async Task SelectAsync_ManyGroupsLastCandidate_ChoosesCandidate()
{
// Arrange
var endpoints = new MatcherEndpoint[]
var endpoints = new RouteEndpoint[]
{
CreateEndpoint("/test1"),
CreateEndpoint("/test2"),
@ -152,7 +150,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
public async Task SelectAsync_MultipleValidCandidatesInGroup_ReportsAmbiguity()
{
// Arrange
var endpoints = new MatcherEndpoint[] { CreateEndpoint("/test1"), CreateEndpoint("/test2"), CreateEndpoint("/test3"), };
var endpoints = new RouteEndpoint[] { CreateEndpoint("/test1"), CreateEndpoint("/test2"), CreateEndpoint("/test3"), };
var scores = new int[] { 0, 1, 1 };
var candidateSet = CreateCandidateSet(endpoints, scores);
@ -179,7 +177,7 @@ test: /test3", ex.Message);
public async Task SelectAsync_RunsEndpointSelectorPolicies()
{
// Arrange
var endpoints = new MatcherEndpoint[] { CreateEndpoint("/test1"), CreateEndpoint("/test2"), CreateEndpoint("/test3"), };
var endpoints = new RouteEndpoint[] { CreateEndpoint("/test1"), CreateEndpoint("/test2"), CreateEndpoint("/test3"), };
var scores = new int[] { 0, 0, 1 };
var candidateSet = CreateCandidateSet(endpoints, scores);
@ -206,22 +204,27 @@ test: /test3", ex.Message);
Assert.Same(endpoints[2], feature.Endpoint);
}
private static (HttpContext httpContext, IEndpointFeature feature) CreateContext()
private static (HttpContext httpContext, EndpointFeature feature) CreateContext()
{
return (new DefaultHttpContext(), new EndpointFeature());
var feature = new EndpointFeature();
var httpContext = new DefaultHttpContext();
httpContext.Features.Set<IEndpointFeature>(feature);
httpContext.Features.Set<IRouteValuesFeature>(feature);
return (httpContext, feature);
}
private static MatcherEndpoint CreateEndpoint(string template)
private static RouteEndpoint CreateEndpoint(string template)
{
return new MatcherEndpoint(
MatcherEndpoint.EmptyInvoker,
return new RouteEndpoint(
TestConstants.EmptyRequestDelegate,
RoutePatternFactory.Parse(template),
0,
EndpointMetadataCollection.Empty,
$"test: {template}");
}
private static CandidateSet CreateCandidateSet(MatcherEndpoint[] endpoints, int[] scores)
private static CandidateSet CreateCandidateSet(RouteEndpoint[] endpoints, int[] scores)
{
return new CandidateSet(endpoints, scores);
}
@ -231,4 +234,4 @@ test: /test3", ex.Message);
return new DefaultEndpointSelector(policies);
}
}
}
}

View File

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing.Constraints;
using Microsoft.AspNetCore.Routing.Patterns;
using Microsoft.Extensions.Options;
@ -876,14 +877,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
policies);
}
private MatcherEndpoint CreateEndpoint(
private RouteEndpoint CreateEndpoint(
string template,
object defaults = null,
object constraints = null,
params object[] metadata)
{
return new MatcherEndpoint(
MatcherEndpoint.EmptyInvoker,
return new RouteEndpoint(
TestConstants.EmptyRequestDelegate,
RoutePatternFactory.Parse(template, new RouteValueDictionary(defaults), new RouteValueDictionary(constraints)),
0,
new EndpointMetadataCollection(metadata),

View File

@ -20,10 +20,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint, keys, values);
MatcherAssert.AssertMatch(feature, httpContext, endpoint, keys, values);
}
internal override Matcher CreateMatcher(params MatcherEndpoint[] endpoints)
internal override Matcher CreateMatcher(params RouteEndpoint[] endpoints)
{
var services = new ServiceCollection()
.AddLogging()

View File

@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing.Patterns;
using Microsoft.Extensions.DependencyInjection;
using Moq;
@ -15,10 +16,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
// so we're reusing the services here.
public class DfaMatcherTest
{
private MatcherEndpoint CreateEndpoint(string template, int order, object defaults = null, EndpointMetadataCollection metadata = null)
private RouteEndpoint CreateEndpoint(string template, int order, object defaults = null, EndpointMetadataCollection metadata = null)
{
return new MatcherEndpoint(
MatcherEndpoint.EmptyInvoker,
return new RouteEndpoint(
TestConstants.EmptyRequestDelegate,
RoutePatternFactory.Parse(template, defaults, parameterPolicies: null),
order,
metadata ?? EndpointMetadataCollection.Empty,
@ -54,11 +55,9 @@ namespace Microsoft.AspNetCore.Routing.Matching
var matcher = CreateDfaMatcher(endpointDataSource);
var httpContext = new DefaultHttpContext();
var (httpContext, endpointFeature) = CreateHttpContext();
httpContext.Request.Path = "/1";
var endpointFeature = new EndpointFeature();
// Act
await matcher.MatchAsync(httpContext, endpointFeature);
@ -77,11 +76,9 @@ namespace Microsoft.AspNetCore.Routing.Matching
var matcher = CreateDfaMatcher(endpointDataSource);
var httpContext = new DefaultHttpContext();
var (httpContext, endpointFeature) = CreateHttpContext();
httpContext.Request.Path = "/One";
var endpointFeature = new EndpointFeature();
// Act
await matcher.MatchAsync(httpContext, endpointFeature);
@ -104,11 +101,9 @@ namespace Microsoft.AspNetCore.Routing.Matching
var matcher = CreateDfaMatcher(endpointDataSource);
var httpContext = new DefaultHttpContext();
var (httpContext, endpointFeature) = CreateHttpContext();
httpContext.Request.Path = "/Teams";
var endpointFeature = new EndpointFeature();
// Act
await matcher.MatchAsync(httpContext, endpointFeature);
@ -125,7 +120,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpointSelector = new Mock<EndpointSelector>();
endpointSelector
.Setup(s => s.SelectAsync(It.IsAny<HttpContext>(), It.IsAny<IEndpointFeature>(), It.IsAny<CandidateSet>()))
.Setup(s => s.SelectAsync(It.IsAny<HttpContext>(), It.IsAny<EndpointFeature>(), It.IsAny<CandidateSet>()))
.Callback<HttpContext, IEndpointFeature, CandidateSet>((c, f, cs) =>
{
Assert.Equal(2, cs.Count);
@ -152,16 +147,25 @@ namespace Microsoft.AspNetCore.Routing.Matching
var matcher = CreateDfaMatcher(endpointDataSource, endpointSelector.Object);
var httpContext = new DefaultHttpContext();
var (httpContext, endpointFeature) = CreateHttpContext();
httpContext.Request.Path = "/Teams";
var endpointFeature = new EndpointFeature();
// Act
await matcher.MatchAsync(httpContext, endpointFeature);
// Assert
Assert.Equal(endpoint2, endpointFeature.Endpoint);
}
private (HttpContext httpContext, EndpointFeature feature) CreateHttpContext()
{
var feature = new EndpointFeature();
var httpContext = new DefaultHttpContext();
httpContext.Features.Set<IEndpointFeature>(feature);
httpContext.Features.Set<IRouteValuesFeature>(feature);
return (httpContext, feature);
}
}
}

View File

@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.AspNetCore.Routing.TestObjects;
using Microsoft.AspNetCore.Http;
using Xunit;
namespace Microsoft.AspNetCore.Routing.Matching
@ -13,8 +13,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
public void Compare_EndpointWithMetadata_MoreSpecific()
{
// Arrange
var endpoint1 = new TestEndpoint(new EndpointMetadataCollection(new object[] { new TestMetadata(), }), "test1");
var endpoint2 = new TestEndpoint(new EndpointMetadataCollection(new object[] { }), "test2");
var endpoint1 = new Endpoint(TestConstants.EmptyRequestDelegate, new EndpointMetadataCollection(new object[] { new TestMetadata(), }), "test1");
var endpoint2 = new Endpoint(TestConstants.EmptyRequestDelegate, new EndpointMetadataCollection(new object[] { }), "test2");
// Act
var result = EndpointMetadataComparer<TestMetadata>.Default.Compare(endpoint1, endpoint2);
@ -27,8 +27,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
public void Compare_EndpointWithMetadata_ReverseOrder_MoreSpecific()
{
// Arrange
var endpoint1 = new TestEndpoint(new EndpointMetadataCollection(new object[] { }), "test1");
var endpoint2 = new TestEndpoint(new EndpointMetadataCollection(new object[] { new TestMetadata(), }), "test2");
var endpoint1 = new Endpoint(TestConstants.EmptyRequestDelegate, new EndpointMetadataCollection(new object[] { }), "test1");
var endpoint2 = new Endpoint(TestConstants.EmptyRequestDelegate, new EndpointMetadataCollection(new object[] { new TestMetadata(), }), "test2");
// Act
var result = EndpointMetadataComparer<TestMetadata>.Default.Compare(endpoint1, endpoint2);
@ -41,8 +41,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
public void Compare_BothEndpointsWithMetadata_Equal()
{
// Arrange
var endpoint1 = new TestEndpoint(new EndpointMetadataCollection(new object[] { new TestMetadata(), }), "test1");
var endpoint2 = new TestEndpoint(new EndpointMetadataCollection(new object[] { new TestMetadata(), }), "test2");
var endpoint1 = new Endpoint(TestConstants.EmptyRequestDelegate, new EndpointMetadataCollection(new object[] { new TestMetadata(), }), "test1");
var endpoint2 = new Endpoint(TestConstants.EmptyRequestDelegate, new EndpointMetadataCollection(new object[] { new TestMetadata(), }), "test2");
// Act
var result = EndpointMetadataComparer<TestMetadata>.Default.Compare(endpoint1, endpoint2);
@ -55,8 +55,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
public void Compare_BothEndpointsWithoutMetadata_Equal()
{
// Arrange
var endpoint1 = new TestEndpoint(new EndpointMetadataCollection(new object[] { }), "test1");
var endpoint2 = new TestEndpoint(new EndpointMetadataCollection(new object[] { }), "test2");
var endpoint1 = new Endpoint(TestConstants.EmptyRequestDelegate, new EndpointMetadataCollection(new object[] { }), "test1");
var endpoint2 = new Endpoint(TestConstants.EmptyRequestDelegate, new EndpointMetadataCollection(new object[] { }), "test2");
// Act
var result = EndpointMetadataComparer<TestMetadata>.Default.Compare(endpoint1, endpoint2);
@ -69,8 +69,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
public void Sort_EndpointWithMetadata_FirstInList()
{
// Arrange
var endpoint1 = new TestEndpoint(new EndpointMetadataCollection(new object[] { new TestMetadata(), }), "test1");
var endpoint2 = new TestEndpoint(new EndpointMetadataCollection(new object[] { }), "test2");
var endpoint1 = new Endpoint(TestConstants.EmptyRequestDelegate, new EndpointMetadataCollection(new object[] { new TestMetadata(), }), "test1");
var endpoint2 = new Endpoint(TestConstants.EmptyRequestDelegate, new EndpointMetadataCollection(new object[] { }), "test2");
var list = new List<Endpoint>() { endpoint2, endpoint1, };

View File

@ -34,7 +34,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint, keys, values);
MatcherAssert.AssertMatch(feature, httpContext, endpoint, keys, values);
}
[Fact]
@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint, new { b = "17", c = "18", });
MatcherAssert.AssertMatch(feature, httpContext, endpoint, new { b = "17", c = "18", });
}
[Fact]
@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint, new { b = "17", c = "18", d = "19" });
MatcherAssert.AssertMatch(feature, httpContext, endpoint, new { b = "17", c = "18", d = "19" });
}
[Theory]
@ -89,7 +89,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertNotMatch(feature);
MatcherAssert.AssertNotMatch(feature, httpContext);
}
[Theory]
@ -121,7 +121,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint, keys, values);
MatcherAssert.AssertMatch(feature, httpContext, endpoint, keys, values);
}
[Theory]
@ -144,7 +144,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertNotMatch(feature);
MatcherAssert.AssertNotMatch(feature, httpContext);
}
[Theory]
@ -168,7 +168,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint, keys, values);
MatcherAssert.AssertMatch(feature, httpContext, endpoint, keys, values);
}
// Historically catchall segments don't match an empty segment, but only if it's
@ -188,7 +188,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertNotMatch(feature);
MatcherAssert.AssertNotMatch(feature, httpContext);
// Need to access these to prevent a warning from the xUnit analyzer.
// Some of these tests will match (and process the values) and some will not.
@ -223,7 +223,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint, keys, values);
MatcherAssert.AssertMatch(feature, httpContext, endpoint, keys, values);
}
[Theory]
@ -243,7 +243,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertNotMatch(feature);
MatcherAssert.AssertNotMatch(feature, httpContext);
}
[Theory]
@ -272,7 +272,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint, keys, values);
MatcherAssert.AssertMatch(feature, httpContext, endpoint, keys, values);
}
[Theory]
@ -298,7 +298,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertNotMatch(feature);
MatcherAssert.AssertNotMatch(feature, httpContext);
}
// Most of are copied from old routing tests that date back to the VS 2010 era. Enjoy!
@ -323,7 +323,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint, keys, values);
MatcherAssert.AssertMatch(feature, httpContext, endpoint, keys, values);
}
[Theory]
@ -353,7 +353,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, expected, ignoreValues: true);
MatcherAssert.AssertMatch(feature, httpContext, expected, ignoreValues: true);
}
[Theory]
@ -387,7 +387,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, expected, ignoreValues: true);
MatcherAssert.AssertMatch(feature, httpContext, expected, ignoreValues: true);
}
[Theory]
@ -440,7 +440,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, expected, ignoreValues: true);
MatcherAssert.AssertMatch(feature, httpContext, expected, ignoreValues: true);
}
}
}
}

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing.Patterns;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
@ -28,7 +29,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint);
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
}
[Fact]
@ -44,7 +45,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint);
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
}
[Fact]
@ -60,7 +61,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint);
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
}
@ -94,7 +95,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint);
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
}
[Fact]
@ -110,7 +111,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint);
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
}
[Fact]
@ -126,7 +127,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint);
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
}
[Fact]
@ -142,7 +143,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint);
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
}
[Fact] // This matches because the endpoint accepts OPTIONS
@ -158,7 +159,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint);
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
}
[Fact]
@ -174,7 +175,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint);
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
}
[Fact] // When all of the candidates handles specific verbs, use a 405 endpoint
@ -197,7 +198,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
Assert.Same(HttpMethodMatcherPolicy.Http405EndpointDisplayName, feature.Endpoint.DisplayName);
// Invoke the endpoint
await feature.Invoker((c) => Task.CompletedTask)(httpContext);
await feature.Endpoint.RequestDelegate(httpContext);
Assert.Equal(405, httpContext.Response.StatusCode);
Assert.Equal("DELETE, GET, PUT", httpContext.Response.Headers["Allow"]);
}
@ -216,7 +217,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertNotMatch(feature);
MatcherAssert.AssertNotMatch(feature, httpContext);
}
[Fact] // When one of the candidates handles all verbs, dont use a 405 endpoint
@ -233,7 +234,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertNotMatch(feature);
MatcherAssert.AssertNotMatch(feature, httpContext);
}
[Fact]
@ -250,7 +251,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint1);
MatcherAssert.AssertMatch(feature, httpContext, endpoint1);
}
[Fact]
@ -267,7 +268,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint1);
MatcherAssert.AssertMatch(feature, httpContext, endpoint1);
}
[Fact] // The non-http-method-specific endpoint is part of the same candidate set
@ -284,10 +285,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint2, ignoreValues: true);
MatcherAssert.AssertMatch(feature, httpContext, endpoint2, ignoreValues: true);
}
private static Matcher CreateMatcher(params MatcherEndpoint[] endpoints)
private static Matcher CreateMatcher(params RouteEndpoint[] endpoints)
{
var services = new ServiceCollection()
.AddOptions()
@ -304,7 +305,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
return builder.Build();
}
internal static (HttpContext httpContext, IEndpointFeature feature) CreateContext(
internal static (HttpContext httpContext, EndpointFeature feature) CreateContext(
string path,
string httpMethod,
bool corsPreflight = false)
@ -321,10 +322,11 @@ namespace Microsoft.AspNetCore.Routing.Matching
var feature = new EndpointFeature();
httpContext.Features.Set<IEndpointFeature>(feature);
httpContext.Features.Set<IRouteValuesFeature>(feature);
return (httpContext, feature);
}
internal static MatcherEndpoint CreateEndpoint(
internal static RouteEndpoint CreateEndpoint(
string template,
object defaults = null,
object constraints = null,
@ -339,15 +341,15 @@ namespace Microsoft.AspNetCore.Routing.Matching
}
var displayName = "endpoint: " + template + " " + string.Join(", ", httpMethods ?? new[] { "(any)" });
return new MatcherEndpoint(
MatcherEndpoint.EmptyInvoker,
return new RouteEndpoint(
TestConstants.EmptyRequestDelegate,
RoutePatternFactory.Parse(template, defaults, constraints),
order,
new EndpointMetadataCollection(metadata),
displayName);
}
internal (Matcher matcher, MatcherEndpoint endpoint) CreateMatcher(string template)
internal (Matcher matcher, RouteEndpoint endpoint) CreateMatcher(string template)
{
var endpoint = CreateEndpoint(template);
return (CreateMatcher(endpoint), endpoint);

View File

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing.Patterns;
using Xunit;
using static Microsoft.AspNetCore.Routing.Matching.HttpMethodMatcherPolicy;
@ -276,7 +277,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
});
}
private static MatcherEndpoint CreateEndpoint(string template, HttpMethodMetadata httpMethodMetadata)
private static RouteEndpoint CreateEndpoint(string template, HttpMethodMetadata httpMethodMetadata)
{
var metadata = new List<object>();
if (httpMethodMetadata != null)
@ -284,8 +285,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
metadata.Add(httpMethodMetadata);
}
return new MatcherEndpoint(
MatcherEndpoint.EmptyInvoker,
return new RouteEndpoint(
TestConstants.EmptyRequestDelegate,
RoutePatternFactory.Parse(template),
0,
new EndpointMetadataCollection(metadata),

View File

@ -4,28 +4,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Xunit.Sdk;
namespace Microsoft.AspNetCore.Routing.Matching
{
internal static class MatcherAssert
{
public static void AssertMatch(IEndpointFeature feature, Endpoint expected)
public static void AssertMatch(EndpointFeature feature, HttpContext context, Endpoint expected)
{
AssertMatch(feature, expected, new RouteValueDictionary());
AssertMatch(feature, context, expected, new RouteValueDictionary());
}
public static void AssertMatch(IEndpointFeature feature, Endpoint expected, bool ignoreValues)
public static void AssertMatch(EndpointFeature feature, HttpContext context, Endpoint expected, bool ignoreValues)
{
AssertMatch(feature, expected, new RouteValueDictionary(), ignoreValues);
AssertMatch(feature, context, expected, new RouteValueDictionary(), ignoreValues);
}
public static void AssertMatch(IEndpointFeature feature, Endpoint expected, object values)
public static void AssertMatch(EndpointFeature feature, HttpContext context, Endpoint expected, object values)
{
AssertMatch(feature, expected, new RouteValueDictionary(values));
AssertMatch(feature, context, expected, new RouteValueDictionary(values));
}
public static void AssertMatch(IEndpointFeature feature, Endpoint expected, string[] keys, string[] values)
public static void AssertMatch(EndpointFeature feature, HttpContext context, Endpoint expected, string[] keys, string[] values)
{
keys = keys ?? Array.Empty<string>();
values = values ?? Array.Empty<string>();
@ -36,11 +38,12 @@ namespace Microsoft.AspNetCore.Routing.Matching
}
var zipped = keys.Zip(values, (k, v) => new KeyValuePair<string, object>(k, v));
AssertMatch(feature, expected, new RouteValueDictionary(zipped));
AssertMatch(feature, context, expected, new RouteValueDictionary(zipped));
}
public static void AssertMatch(
IEndpointFeature feature,
EndpointFeature feature,
HttpContext context,
Endpoint expected,
RouteValueDictionary values,
bool ignoreValues = false)
@ -50,39 +53,41 @@ namespace Microsoft.AspNetCore.Routing.Matching
throw new XunitException($"Was expected to match '{expected.DisplayName}' but did not match.");
}
if (feature.Values == null)
var actualValues = context.Features.Get<IRouteValuesFeature>().RouteValues;
if (actualValues == null)
{
throw new XunitException("Values is null.");
throw new XunitException("RouteValues is null.");
}
if (!object.ReferenceEquals(expected, feature.Endpoint))
{
throw new XunitException(
$"Was expected to match '{expected.DisplayName}' but matched " +
$"'{feature.Endpoint.DisplayName}' with values: {FormatRouteValues(feature.Values)}.");
$"'{feature.Endpoint.DisplayName}' with values: {FormatRouteValues(actualValues)}.");
}
if (!ignoreValues)
{
// Note: this comparison is intended for unit testing, and is stricter than necessary to make tests
// more precise. Route value comparisons in product code are more flexible than a simple .Equals.
if (values.Count != feature.Values.Count ||
!values.OrderBy(kvp => kvp.Key).SequenceEqual(feature.Values.OrderBy(kvp => kvp.Key)))
if (values.Count != actualValues.Count ||
!values.OrderBy(kvp => kvp.Key).SequenceEqual(actualValues.OrderBy(kvp => kvp.Key)))
{
throw new XunitException(
$"Was expected to match '{expected.DisplayName}' with values {FormatRouteValues(values)} but matched " +
$"values: {FormatRouteValues(feature.Values)}.");
$"values: {FormatRouteValues(actualValues)}.");
}
}
}
public static void AssertNotMatch(IEndpointFeature feature)
public static void AssertNotMatch(EndpointFeature feature, HttpContext context)
{
if (feature.Endpoint != null)
{
throw new XunitException(
$"Was expected not to match '{feature.Endpoint.DisplayName}' " +
$"but matched with values: {FormatRouteValues(feature.Values)}.");
$"but matched with values: {FormatRouteValues(context.Features.Get<IRouteValuesFeature>().RouteValues)}.");
}
}
@ -91,4 +96,4 @@ namespace Microsoft.AspNetCore.Routing.Matching
return "{" + string.Join(", ", values.Select(kvp => $"{kvp.Key} = '{kvp.Value}'")) + "}";
}
}
}
}

View File

@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint);
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
}
[Fact]
@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint);
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
}
[Fact]
@ -47,7 +47,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint);
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
}
[Theory]
@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint);
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
}
// Some matchers will optimize for the ASCII case
@ -81,7 +81,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint);
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
}
// Matchers should operate on the decoded representation - a matcher that calls
@ -99,7 +99,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint);
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
}
[Theory]
@ -119,7 +119,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertNotMatch(feature);
MatcherAssert.AssertNotMatch(feature, httpContext);
}
[Theory]
@ -136,7 +136,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint);
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
}
// Matchers do their own 'splitting' of the path into segments, so including
@ -159,7 +159,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint);
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
}
// Matchers do their own 'splitting' of the path into segments, so including
@ -190,7 +190,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertNotMatch(feature);
MatcherAssert.AssertNotMatch(feature, httpContext);
}
[Fact]
@ -205,7 +205,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint, values);
MatcherAssert.AssertMatch(feature, httpContext, endpoint, values);
}
[Fact]
@ -220,7 +220,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint, values);
MatcherAssert.AssertMatch(feature, httpContext, endpoint, values);
}
[Fact]
@ -235,7 +235,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint, values);
MatcherAssert.AssertMatch(feature, httpContext, endpoint, values);
}
[Fact]
@ -255,7 +255,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint, values);
MatcherAssert.AssertMatch(feature, httpContext, endpoint, values);
}
[Theory]
@ -273,7 +273,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertNotMatch(feature);
MatcherAssert.AssertNotMatch(feature, httpContext);
}
[Theory]
@ -294,7 +294,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertMatch(feature, endpoint, keys, values);
MatcherAssert.AssertMatch(feature, httpContext, endpoint, keys, values);
}
[Theory]
@ -323,7 +323,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
await matcher.MatchAsync(httpContext, feature);
// Assert
MatcherAssert.AssertNotMatch(feature);
MatcherAssert.AssertNotMatch(feature, httpContext);
}
}
}

View File

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing.Patterns;
using Microsoft.Extensions.DependencyInjection;
@ -11,9 +12,9 @@ namespace Microsoft.AspNetCore.Routing.Matching
{
public abstract partial class MatcherConformanceTest
{
internal abstract Matcher CreateMatcher(params MatcherEndpoint[] endpoints);
internal abstract Matcher CreateMatcher(params RouteEndpoint[] endpoints);
internal static (HttpContext httpContext, IEndpointFeature feature) CreateContext(string path)
internal static (HttpContext httpContext, EndpointFeature feature) CreateContext(string path)
{
var httpContext = new DefaultHttpContext();
httpContext.Request.Method = "TEST";
@ -22,6 +23,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
var feature = new EndpointFeature();
httpContext.Features.Set<IEndpointFeature>(feature);
httpContext.Features.Set<IRouteValuesFeature>(feature);
return (httpContext, feature);
}
@ -34,21 +36,21 @@ namespace Microsoft.AspNetCore.Routing.Matching
return services.BuildServiceProvider();
}
internal static MatcherEndpoint CreateEndpoint(
internal static RouteEndpoint CreateEndpoint(
string template,
object defaults = null,
object constraints = null,
int? order = null)
{
return new MatcherEndpoint(
MatcherEndpoint.EmptyInvoker,
return new RouteEndpoint(
TestConstants.EmptyRequestDelegate,
RoutePatternFactory.Parse(template, defaults, constraints),
order ?? 0,
EndpointMetadataCollection.Empty,
"endpoint: " + template);
}
internal (Matcher matcher, MatcherEndpoint endpoint) CreateMatcher(string template)
internal (Matcher matcher, RouteEndpoint endpoint) CreateMatcher(string template)
{
var endpoint = CreateEndpoint(template);
return (CreateMatcher(endpoint), endpoint);

View File

@ -2,12 +2,13 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing.Patterns;
using Xunit;
namespace Microsoft.AspNetCore.Routing.Matching
{
public class MatcherEndpointComparerTest
public class RouteEndpointComparerTest
{
[Fact]
public void Compare_PrefersOrder_IfDifferent()
@ -198,7 +199,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint7 = CreateEndpoint("/bar{baz}", order: 0, new TestMetadata1(), new TestMetadata2());
// Endpoints listed in reverse of the desired order.
var list = new List<MatcherEndpoint>() { endpoint7, endpoint6, endpoint5, endpoint4, endpoint3, endpoint2, endpoint1, };
var list = new List<RouteEndpoint>() { endpoint7, endpoint6, endpoint5, endpoint4, endpoint3, endpoint2, endpoint1, };
var comparer = CreateComparer(new TestMetadata1Policy(), new TestMetadata2Policy());
@ -217,19 +218,19 @@ namespace Microsoft.AspNetCore.Routing.Matching
e => Assert.Same(endpoint7, e));
}
private static MatcherEndpoint CreateEndpoint(string template, int order, params object[] metadata)
private static RouteEndpoint CreateEndpoint(string template, int order, params object[] metadata)
{
return new MatcherEndpoint(
MatcherEndpoint.EmptyInvoker,
return new RouteEndpoint(
TestConstants.EmptyRequestDelegate,
RoutePatternFactory.Parse(template),
order,
new EndpointMetadataCollection(metadata),
"test: " + template);
}
private static MatcherEndpointComparer CreateComparer(params IEndpointComparerPolicy[] policies)
private static RouteEndpointComparer CreateComparer(params IEndpointComparerPolicy[] policies)
{
return new MatcherEndpointComparer(policies);
return new RouteEndpointComparer(policies);
}
private class TestMetadata1

View File

@ -4,6 +4,7 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
namespace Microsoft.AspNetCore.Routing.Matching
{
@ -17,7 +18,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
_inner = inner;
}
public async override Task MatchAsync(HttpContext httpContext, IEndpointFeature feature)
public async override Task MatchAsync(HttpContext httpContext, EndpointFeature feature)
{
if (httpContext == null)
{
@ -34,7 +35,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
if (context.Handler != null)
{
feature.Values = context.RouteData.Values;
feature.RouteValues = context.RouteData.Values;
await context.Handler(httpContext);
}
}

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing.Patterns;
using Microsoft.Extensions.Options;
@ -13,15 +14,15 @@ namespace Microsoft.AspNetCore.Routing.Matching
internal class RouteMatcherBuilder : MatcherBuilder
{
private readonly IInlineConstraintResolver _constraintResolver;
private readonly List<MatcherEndpoint> _endpoints;
private readonly List<RouteEndpoint> _endpoints;
public RouteMatcherBuilder()
{
_constraintResolver = new DefaultInlineConstraintResolver(Options.Create(new RouteOptions()));
_endpoints = new List<MatcherEndpoint>();
_endpoints = new List<RouteEndpoint>();
}
public override void AddEndpoint(MatcherEndpoint endpoint)
public override void AddEndpoint(RouteEndpoint endpoint)
{
_endpoints.Add(endpoint);
}
@ -73,10 +74,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
private class SelectorRouter : IRouter
{
private readonly EndpointSelector _selector;
private readonly MatcherEndpoint[] _candidates;
private readonly RouteEndpoint[] _candidates;
private readonly int[] _scores;
public SelectorRouter(EndpointSelector selector, MatcherEndpoint[] candidates)
public SelectorRouter(EndpointSelector selector, RouteEndpoint[] candidates)
{
_selector = selector;
_candidates = candidates;
@ -91,7 +92,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
public async Task RouteAsync(RouteContext context)
{
var feature = context.HttpContext.Features.Get<IEndpointFeature>();
var feature = (EndpointFeature)context.HttpContext.Features.Get<IEndpointFeature>();
// This is needed due to a quirk of our tests - they reuse the endpoint feature
// across requests.

View File

@ -5,7 +5,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
{
public class RouteMatcherConformanceTest : FullFeaturedMatcherConformanceTest
{
internal override Matcher CreateMatcher(params MatcherEndpoint[] endpoints)
internal override Matcher CreateMatcher(params RouteEndpoint[] endpoints)
{
var builder = new RouteMatcherBuilder();
for (int i = 0; i < endpoints.Length; i++)

View File

@ -4,6 +4,7 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing.Tree;
namespace Microsoft.AspNetCore.Routing.Matching
@ -18,7 +19,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
_inner = inner;
}
public async override Task MatchAsync(HttpContext httpContext, IEndpointFeature feature)
public async override Task MatchAsync(HttpContext httpContext, EndpointFeature feature)
{
if (httpContext == null)
{
@ -35,7 +36,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
if (context.Handler != null)
{
feature.Values = context.RouteData.Values;
feature.RouteValues = context.RouteData.Values;
await context.Handler(httpContext);
}
}

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing.Internal;
using Microsoft.AspNetCore.Routing.Template;
using Microsoft.AspNetCore.Routing.Tree;
@ -16,14 +17,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
{
internal class TreeRouterMatcherBuilder : MatcherBuilder
{
private readonly List<MatcherEndpoint> _endpoints;
private readonly List<RouteEndpoint> _endpoints;
public TreeRouterMatcherBuilder()
{
_endpoints = new List<MatcherEndpoint>();
_endpoints = new List<RouteEndpoint>();
}
public override void AddEndpoint(MatcherEndpoint endpoint)
public override void AddEndpoint(RouteEndpoint endpoint)
{
_endpoints.Add(endpoint);
}
@ -48,7 +49,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
{
var candidates = group.ToArray();
// MatcherEndpoint.Values contains the default values parsed from the template
// RouteEndpoint.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 endpoint = group.First();
@ -75,10 +76,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
private class SelectorRouter : IRouter
{
private readonly EndpointSelector _selector;
private readonly MatcherEndpoint[] _candidates;
private readonly RouteEndpoint[] _candidates;
private readonly int[] _scores;
public SelectorRouter(EndpointSelector selector, MatcherEndpoint[] candidates)
public SelectorRouter(EndpointSelector selector, RouteEndpoint[] candidates)
{
_selector = selector;
_candidates = candidates;
@ -93,7 +94,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
public async Task RouteAsync(RouteContext context)
{
var feature = context.HttpContext.Features.Get<IEndpointFeature>();
var feature = (EndpointFeature)context.HttpContext.Features.Get<IEndpointFeature>();
// This is needed due to a quirk of our tests - they reuse the endpoint feature.
feature.Endpoint = null;

View File

@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
return Task.CompletedTask;
}
internal override Matcher CreateMatcher(params MatcherEndpoint[] endpoints)
internal override Matcher CreateMatcher(params RouteEndpoint[] endpoints)
{
var builder = new TreeRouterMatcherBuilder();
for (var i = 0; i < endpoints.Length; i++)

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing.Internal;
using Microsoft.AspNetCore.Routing.Matching;
using Microsoft.AspNetCore.Routing.Patterns;
@ -34,7 +35,7 @@ namespace Microsoft.AspNetCore.Routing
Assert.NotNull(finder.NamedMatches);
Assert.True(finder.NamedMatches.TryGetValue("named", out var namedMatches));
var namedMatch = Assert.Single(namedMatches);
var actual = Assert.IsType<MatcherEndpoint>(namedMatch.Match.Entry.Data);
var actual = Assert.IsType<RouteEndpoint>(namedMatch.Match.Entry.Data);
Assert.Same(endpoint2, actual);
}
@ -55,8 +56,8 @@ namespace Microsoft.AspNetCore.Routing
Assert.NotNull(finder.NamedMatches);
Assert.True(finder.NamedMatches.TryGetValue("named", out var namedMatches));
Assert.Equal(2, namedMatches.Count);
Assert.Same(endpoint2, Assert.IsType<MatcherEndpoint>(namedMatches[0].Match.Entry.Data));
Assert.Same(endpoint3, Assert.IsType<MatcherEndpoint>(namedMatches[1].Match.Entry.Data));
Assert.Same(endpoint2, Assert.IsType<RouteEndpoint>(namedMatches[0].Match.Entry.Data));
Assert.Same(endpoint3, Assert.IsType<RouteEndpoint>(namedMatches[1].Match.Entry.Data));
}
[Fact]
@ -76,8 +77,8 @@ namespace Microsoft.AspNetCore.Routing
Assert.NotNull(finder.NamedMatches);
Assert.True(finder.NamedMatches.TryGetValue("named", out var namedMatches));
Assert.Equal(2, namedMatches.Count);
Assert.Same(endpoint2, Assert.IsType<MatcherEndpoint>(namedMatches[0].Match.Entry.Data));
Assert.Same(endpoint3, Assert.IsType<MatcherEndpoint>(namedMatches[1].Match.Entry.Data));
Assert.Same(endpoint2, Assert.IsType<RouteEndpoint>(namedMatches[0].Match.Entry.Data));
Assert.Same(endpoint3, Assert.IsType<RouteEndpoint>(namedMatches[1].Match.Entry.Data));
}
[Fact]
@ -97,7 +98,7 @@ namespace Microsoft.AspNetCore.Routing
// Assert 1
Assert.NotNull(finder.AllMatches);
var match = Assert.Single(finder.AllMatches);
var actual = Assert.IsType<MatcherEndpoint>(match.Entry.Data);
var actual = Assert.IsType<RouteEndpoint>(match.Entry.Data);
Assert.Same(endpoint1, actual);
// Arrange 2
@ -127,22 +128,22 @@ namespace Microsoft.AspNetCore.Routing
finder.AllMatches,
(m) =>
{
actual = Assert.IsType<MatcherEndpoint>(m.Entry.Data);
actual = Assert.IsType<RouteEndpoint>(m.Entry.Data);
Assert.Same(endpoint1, actual);
},
(m) =>
{
actual = Assert.IsType<MatcherEndpoint>(m.Entry.Data);
actual = Assert.IsType<RouteEndpoint>(m.Entry.Data);
Assert.Same(endpoint2, actual);
},
(m) =>
{
actual = Assert.IsType<MatcherEndpoint>(m.Entry.Data);
actual = Assert.IsType<RouteEndpoint>(m.Entry.Data);
Assert.Same(endpoint3, actual);
},
(m) =>
{
actual = Assert.IsType<MatcherEndpoint>(m.Entry.Data);
actual = Assert.IsType<RouteEndpoint>(m.Entry.Data);
Assert.Same(endpoint4, actual);
});
}
@ -231,7 +232,7 @@ namespace Microsoft.AspNetCore.Routing
objectPool);
}
private MatcherEndpoint CreateEndpoint(
private RouteEndpoint CreateEndpoint(
string template,
object defaults = null,
object requiredValues = null,
@ -249,8 +250,8 @@ namespace Microsoft.AspNetCore.Routing
metadataCollection = new EndpointMetadataCollection(metadata);
}
return new MatcherEndpoint(
MatcherEndpoint.EmptyInvoker,
return new RouteEndpoint(
TestConstants.EmptyRequestDelegate,
RoutePatternFactory.Parse(template, defaults, parameterPolicies: null),
order,
metadataCollection,

View File

@ -0,0 +1,13 @@
// 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.Threading.Tasks;
using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Routing
{
public static class TestConstants
{
internal static readonly RequestDelegate EmptyRequestDelegate = (context) => Task.CompletedTask;
}
}

View File

@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Threading;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNetCore.Routing.TestObjects

View File

@ -1,13 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNetCore.Routing.TestObjects
{
internal class TestEndpoint : Endpoint
{
public TestEndpoint(EndpointMetadataCollection metadata, string displayName)
: base(metadata, displayName)
{
}
}
}

View File

@ -3,6 +3,7 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing.Matching;
namespace Microsoft.AspNetCore.Routing.TestObjects
@ -16,12 +17,12 @@ namespace Microsoft.AspNetCore.Routing.TestObjects
_isHandled = isHandled;
}
public override Task MatchAsync(HttpContext httpContext, IEndpointFeature feature)
public override Task MatchAsync(HttpContext httpContext, EndpointFeature feature)
{
if (_isHandled)
{
feature.Values = new RouteValueDictionary(new { controller = "Home", action = "Index" });
feature.Endpoint = new TestEndpoint(EndpointMetadataCollection.Empty, "Test endpoint");
feature.RouteValues = new RouteValueDictionary(new { controller = "Home", action = "Index" });
feature.Endpoint = new Endpoint(TestConstants.EmptyRequestDelegate, EndpointMetadataCollection.Empty, "Test endpoint");
}
return Task.CompletedTask;