Merge release/2.2
This commit is contained in:
commit
aff4a38865
|
|
@ -2,9 +2,9 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Routing;
|
using Microsoft.AspNetCore.Routing;
|
||||||
using Microsoft.AspNetCore.Routing.Matching;
|
|
||||||
using Microsoft.AspNetCore.Routing.Patterns;
|
using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
|
|
@ -21,8 +21,8 @@ namespace Benchmarks
|
||||||
|
|
||||||
var endpointDataSource = new DefaultEndpointDataSource(new[]
|
var endpointDataSource = new DefaultEndpointDataSource(new[]
|
||||||
{
|
{
|
||||||
new MatcherEndpoint(
|
new RouteEndpoint(
|
||||||
invoker: (next) => (httpContext) =>
|
requestDelegate: (httpContext) =>
|
||||||
{
|
{
|
||||||
var response = httpContext.Response;
|
var response = httpContext.Response;
|
||||||
var payloadLength = _helloWorldPayload.Length;
|
var payloadLength = _helloWorldPayload.Length;
|
||||||
|
|
@ -47,4 +47,4 @@ namespace Benchmarks
|
||||||
app.UseEndpoint();
|
app.UseEndpoint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,9 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Routing.Matching;
|
using Microsoft.AspNetCore.Routing.Matching;
|
||||||
using Microsoft.AspNetCore.Routing.Patterns;
|
using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
using Microsoft.AspNetCore.Routing.Template;
|
using Microsoft.AspNetCore.Routing.Template;
|
||||||
|
|
@ -18,10 +20,10 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
public abstract class EndpointRoutingBenchmarkBase
|
public abstract class EndpointRoutingBenchmarkBase
|
||||||
{
|
{
|
||||||
private protected MatcherEndpoint[] Endpoints;
|
private protected RouteEndpoint[] Endpoints;
|
||||||
private protected HttpContext[] Requests;
|
private protected HttpContext[] Requests;
|
||||||
|
|
||||||
private protected void SetupEndpoints(params MatcherEndpoint[] endpoints)
|
private protected void SetupEndpoints(params RouteEndpoint[] endpoints)
|
||||||
{
|
{
|
||||||
Endpoints = endpoints;
|
Endpoints = endpoints;
|
||||||
}
|
}
|
||||||
|
|
@ -76,8 +78,8 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
var message = new StringBuilder();
|
var message = new StringBuilder();
|
||||||
message.AppendLine($"Validation failed for request {Array.IndexOf(Requests, httpContext)}");
|
message.AppendLine($"Validation failed for request {Array.IndexOf(Requests, httpContext)}");
|
||||||
message.AppendLine($"{httpContext.Request.Method} {httpContext.Request.Path}");
|
message.AppendLine($"{httpContext.Request.Method} {httpContext.Request.Path}");
|
||||||
message.AppendLine($"expected: '{((MatcherEndpoint)expected)?.DisplayName ?? "null"}'");
|
message.AppendLine($"expected: '{((RouteEndpoint)expected)?.DisplayName ?? "null"}'");
|
||||||
message.AppendLine($"actual: '{((MatcherEndpoint)actual)?.DisplayName ?? "null"}'");
|
message.AppendLine($"actual: '{((RouteEndpoint)actual)?.DisplayName ?? "null"}'");
|
||||||
throw new InvalidOperationException(message.ToString());
|
throw new InvalidOperationException(message.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -95,7 +97,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected MatcherEndpoint CreateEndpoint(
|
protected RouteEndpoint CreateEndpoint(
|
||||||
string template,
|
string template,
|
||||||
object defaults = null,
|
object defaults = null,
|
||||||
object constraints = null,
|
object constraints = null,
|
||||||
|
|
@ -108,8 +110,8 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
var endpointMetadata = new List<object>(metadata ?? Array.Empty<object>());
|
var endpointMetadata = new List<object>(metadata ?? Array.Empty<object>());
|
||||||
endpointMetadata.Add(new RouteValuesAddressMetadata(routeName, new RouteValueDictionary(requiredValues)));
|
endpointMetadata.Add(new RouteValuesAddressMetadata(routeName, new RouteValueDictionary(requiredValues)));
|
||||||
|
|
||||||
return new MatcherEndpoint(
|
return new RouteEndpoint(
|
||||||
MatcherEndpoint.EmptyInvoker,
|
(context) => Task.CompletedTask,
|
||||||
RoutePatternFactory.Parse(template, defaults, constraints),
|
RoutePatternFactory.Parse(template, defaults, constraints),
|
||||||
order,
|
order,
|
||||||
new EndpointMetadataCollection(endpointMetadata),
|
new EndpointMetadataCollection(endpointMetadata),
|
||||||
|
|
@ -119,14 +121,15 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
protected (HttpContext httpContext, RouteValueDictionary ambientValues) CreateCurrentRequestContext(
|
protected (HttpContext httpContext, RouteValueDictionary ambientValues) CreateCurrentRequestContext(
|
||||||
object ambientValues = null)
|
object ambientValues = null)
|
||||||
{
|
{
|
||||||
var feature = new EndpointFeature { Values = new RouteValueDictionary(ambientValues) };
|
var feature = new EndpointFeature { RouteValues = new RouteValueDictionary(ambientValues) };
|
||||||
var context = new DefaultHttpContext();
|
var context = new DefaultHttpContext();
|
||||||
context.Features.Set<IEndpointFeature>(feature);
|
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 routeValuesAddressMetadata = endpoint.Metadata.GetMetadata<IRouteValuesAddressMetadata>();
|
||||||
var requiredValues = routeValuesAddressMetadata?.RequiredValues ?? new RouteValueDictionary();
|
var requiredValues = routeValuesAddressMetadata?.RequiredValues ?? new RouteValueDictionary();
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Routing.LinkGeneration
|
||||||
|
|
||||||
private void SetupEndpoints()
|
private void SetupEndpoints()
|
||||||
{
|
{
|
||||||
Endpoints = new MatcherEndpoint[243];
|
Endpoints = new RouteEndpoint[243];
|
||||||
Endpoints[0] = CreateEndpoint("/emojis", "Controller1", "Action1", "GET");
|
Endpoints[0] = CreateEndpoint("/emojis", "Controller1", "Action1", "GET");
|
||||||
Endpoints[1] = CreateEndpoint("/events", "Controller2", "Action1", "GET");
|
Endpoints[1] = CreateEndpoint("/events", "Controller2", "Action1", "GET");
|
||||||
Endpoints[2] = CreateEndpoint("/feeds", "Controller3", "Action1", "GET");
|
Endpoints[2] = CreateEndpoint("/feeds", "Controller3", "Action1", "GET");
|
||||||
|
|
@ -1485,7 +1485,7 @@ namespace Microsoft.AspNetCore.Routing.LinkGeneration
|
||||||
return builder.Build();
|
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
|
var requiredValues = new
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
private void SetupEndpoints()
|
private void SetupEndpoints()
|
||||||
{
|
{
|
||||||
Endpoints = new MatcherEndpoint[5160];
|
Endpoints = new RouteEndpoint[5160];
|
||||||
Endpoints[0] = CreateEndpoint("/account", "GET");
|
Endpoints[0] = CreateEndpoint("/account", "GET");
|
||||||
Endpoints[1] = CreateEndpoint("/analyze", "POST");
|
Endpoints[1] = CreateEndpoint("/analyze", "POST");
|
||||||
Endpoints[2] = CreateEndpoint("/apis", "GET");
|
Endpoints[2] = CreateEndpoint("/apis", "GET");
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
private void SetupEndpoints()
|
private void SetupEndpoints()
|
||||||
{
|
{
|
||||||
Endpoints = new MatcherEndpoint[3517];
|
Endpoints = new RouteEndpoint[3517];
|
||||||
Endpoints[0] = CreateEndpoint("/account");
|
Endpoints[0] = CreateEndpoint("/account");
|
||||||
Endpoints[1] = CreateEndpoint("/analyze");
|
Endpoints[1] = CreateEndpoint("/analyze");
|
||||||
Endpoints[2] = CreateEndpoint("/apis");
|
Endpoints[2] = CreateEndpoint("/apis");
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
private void SetupEndpoints()
|
private void SetupEndpoints()
|
||||||
{
|
{
|
||||||
Endpoints = new MatcherEndpoint[155];
|
Endpoints = new RouteEndpoint[155];
|
||||||
Endpoints[0] = CreateEndpoint("/emojis");
|
Endpoints[0] = CreateEndpoint("/emojis");
|
||||||
Endpoints[1] = CreateEndpoint("/events");
|
Endpoints[1] = CreateEndpoint("/events");
|
||||||
Endpoints[2] = CreateEndpoint("/feeds");
|
Endpoints[2] = CreateEndpoint("/feeds");
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
[GlobalSetup]
|
[GlobalSetup]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
{
|
{
|
||||||
Endpoints = new MatcherEndpoint[1];
|
Endpoints = new RouteEndpoint[1];
|
||||||
Endpoints[0] = CreateEndpoint("/plaintext");
|
Endpoints[0] = CreateEndpoint("/plaintext");
|
||||||
|
|
||||||
Requests = new HttpContext[1];
|
Requests = new HttpContext[1];
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
|
|
@ -32,7 +33,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
private void SetupEndpoints()
|
private void SetupEndpoints()
|
||||||
{
|
{
|
||||||
Endpoints = new MatcherEndpoint[10];
|
Endpoints = new RouteEndpoint[10];
|
||||||
Endpoints[0] = CreateEndpoint("/another-really-cool-entry");
|
Endpoints[0] = CreateEndpoint("/another-really-cool-entry");
|
||||||
Endpoints[1] = CreateEndpoint("/Some-Entry");
|
Endpoints[1] = CreateEndpoint("/Some-Entry");
|
||||||
Endpoints[2] = CreateEndpoint("/a/path/with/more/segments");
|
Endpoints[2] = CreateEndpoint("/a/path/with/more/segments");
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
private void SetupEndpoints()
|
private void SetupEndpoints()
|
||||||
{
|
{
|
||||||
Endpoints = new MatcherEndpoint[243];
|
Endpoints = new RouteEndpoint[243];
|
||||||
Endpoints[0] = CreateEndpoint("/emojis", "GET");
|
Endpoints[0] = CreateEndpoint("/emojis", "GET");
|
||||||
Endpoints[1] = CreateEndpoint("/events", "GET");
|
Endpoints[1] = CreateEndpoint("/events", "GET");
|
||||||
Endpoints[2] = CreateEndpoint("/feeds", "GET");
|
Endpoints[2] = CreateEndpoint("/feeds", "GET");
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
|
|
@ -22,7 +23,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
[GlobalSetup]
|
[GlobalSetup]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
{
|
{
|
||||||
Endpoints = new MatcherEndpoint[1];
|
Endpoints = new RouteEndpoint[1];
|
||||||
Endpoints[0] = CreateEndpoint("/plaintext");
|
Endpoints[0] = CreateEndpoint("/plaintext");
|
||||||
|
|
||||||
Requests = new HttpContext[1];
|
Requests = new HttpContext[1];
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
|
|
@ -12,17 +13,17 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
// to establish a lower bound for perf comparisons.
|
// to establish a lower bound for perf comparisons.
|
||||||
internal sealed class TrivialMatcher : Matcher
|
internal sealed class TrivialMatcher : Matcher
|
||||||
{
|
{
|
||||||
private readonly MatcherEndpoint _endpoint;
|
private readonly RouteEndpoint _endpoint;
|
||||||
private readonly Candidate[] _candidates;
|
private readonly Candidate[] _candidates;
|
||||||
|
|
||||||
public TrivialMatcher(MatcherEndpoint endpoint)
|
public TrivialMatcher(RouteEndpoint endpoint)
|
||||||
{
|
{
|
||||||
_endpoint = endpoint;
|
_endpoint = endpoint;
|
||||||
|
|
||||||
_candidates = new Candidate[] { new Candidate(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)
|
if (httpContext == null)
|
||||||
{
|
{
|
||||||
|
|
@ -38,7 +39,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
if (string.Equals(_endpoint.RoutePattern.RawText, path, StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(_endpoint.RoutePattern.RawText, path, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
feature.Endpoint = _endpoint;
|
feature.Endpoint = _endpoint;
|
||||||
feature.Values = new RouteValueDictionary();
|
feature.RouteValues = new RouteValueDictionary();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
internal class TrivialMatcherBuilder : MatcherBuilder
|
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);
|
_endpoints.Add(endpoint);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
private void SetupEndpoints()
|
private void SetupEndpoints()
|
||||||
{{
|
{{
|
||||||
Endpoints = new MatcherEndpoint[{3}];
|
Endpoints = new RouteEndpoint[{3}];
|
||||||
{0}
|
{0}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|
@ -94,7 +94,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
return builder.Build();
|
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
|
var requiredValues = new
|
||||||
{{
|
{{
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ namespace RoutingSample.Web
|
||||||
builder.MapHello("/helloworld", "World");
|
builder.MapHello("/helloworld", "World");
|
||||||
|
|
||||||
builder.MapEndpoint(
|
builder.MapEndpoint(
|
||||||
(next) => (httpContext) =>
|
(httpContext) =>
|
||||||
{
|
{
|
||||||
var response = httpContext.Response;
|
var response = httpContext.Response;
|
||||||
var payloadLength = _homePayload.Length;
|
var payloadLength = _homePayload.Length;
|
||||||
|
|
@ -48,7 +48,7 @@ namespace RoutingSample.Web
|
||||||
"/",
|
"/",
|
||||||
"Home");
|
"Home");
|
||||||
builder.MapEndpoint(
|
builder.MapEndpoint(
|
||||||
(next) => (httpContext) =>
|
(httpContext) =>
|
||||||
{
|
{
|
||||||
var response = httpContext.Response;
|
var response = httpContext.Response;
|
||||||
var payloadLength = _plainTextPayload.Length;
|
var payloadLength = _plainTextPayload.Length;
|
||||||
|
|
@ -60,7 +60,7 @@ namespace RoutingSample.Web
|
||||||
"/plaintext",
|
"/plaintext",
|
||||||
"Plaintext");
|
"Plaintext");
|
||||||
builder.MapEndpoint(
|
builder.MapEndpoint(
|
||||||
(next) => (httpContext) =>
|
(httpContext) =>
|
||||||
{
|
{
|
||||||
var response = httpContext.Response;
|
var response = httpContext.Response;
|
||||||
response.StatusCode = 200;
|
response.StatusCode = 200;
|
||||||
|
|
@ -70,7 +70,7 @@ namespace RoutingSample.Web
|
||||||
"/withconstraints/{id:endsWith(_001)}",
|
"/withconstraints/{id:endsWith(_001)}",
|
||||||
"withconstraints");
|
"withconstraints");
|
||||||
builder.MapEndpoint(
|
builder.MapEndpoint(
|
||||||
(next) => (httpContext) =>
|
(httpContext) =>
|
||||||
{
|
{
|
||||||
var response = httpContext.Response;
|
var response = httpContext.Response;
|
||||||
response.StatusCode = 200;
|
response.StatusCode = 200;
|
||||||
|
|
@ -80,7 +80,7 @@ namespace RoutingSample.Web
|
||||||
"/withoptionalconstraints/{id:endsWith(_001)?}",
|
"/withoptionalconstraints/{id:endsWith(_001)?}",
|
||||||
"withoptionalconstraints");
|
"withoptionalconstraints");
|
||||||
builder.MapEndpoint(
|
builder.MapEndpoint(
|
||||||
(next) => (httpContext) =>
|
(httpContext) =>
|
||||||
{
|
{
|
||||||
using (var writer = new StreamWriter(httpContext.Response.Body, Encoding.UTF8, 1024, leaveOpen: true))
|
using (var writer = new StreamWriter(httpContext.Response.Body, Encoding.UTF8, 1024, leaveOpen: true))
|
||||||
{
|
{
|
||||||
|
|
@ -95,7 +95,7 @@ namespace RoutingSample.Web
|
||||||
"DFA Graph",
|
"DFA Graph",
|
||||||
new object[] { new HttpMethodMetadata(new[] { "GET", }) });
|
new object[] { new HttpMethodMetadata(new[] { "GET", }) });
|
||||||
builder.MapEndpoint(
|
builder.MapEndpoint(
|
||||||
(next) => (httpContext) =>
|
(httpContext) =>
|
||||||
{
|
{
|
||||||
var linkGenerator = httpContext.RequestServices.GetRequiredService<LinkGenerator>();
|
var linkGenerator = httpContext.RequestServices.GetRequiredService<LinkGenerator>();
|
||||||
|
|
||||||
|
|
@ -112,7 +112,7 @@ namespace RoutingSample.Web
|
||||||
new RouteValuesAddressMetadata(name: "WithSingleAsteriskCatchAll", requiredValues: new RouteValueDictionary()),
|
new RouteValuesAddressMetadata(name: "WithSingleAsteriskCatchAll", requiredValues: new RouteValueDictionary()),
|
||||||
});
|
});
|
||||||
builder.MapEndpoint(
|
builder.MapEndpoint(
|
||||||
(next) => (httpContext) =>
|
(httpContext) =>
|
||||||
{
|
{
|
||||||
var linkGenerator = httpContext.RequestServices.GetRequiredService<LinkGenerator>();
|
var linkGenerator = httpContext.RequestServices.GetRequiredService<LinkGenerator>();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,30 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Http
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Respresents a logical endpoint in an application.
|
/// Respresents a logical endpoint in an application.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class Endpoint
|
public class Endpoint
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of <see cref="Endpoint"/>.
|
/// Creates a new instance of <see cref="Endpoint"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="requestDelegate">The delegate used to process requests for the endpoint.</param>
|
||||||
/// <param name="metadata">
|
/// <param name="metadata">
|
||||||
/// The endpoint <see cref="EndpointMetadataCollection"/>. May be null.
|
/// The endpoint <see cref="EndpointMetadataCollection"/>. May be null.
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="displayName">
|
/// <param name="displayName">
|
||||||
/// The informational display name of the endpoint. May be null.
|
/// The informational display name of the endpoint. May be null.
|
||||||
/// </param>
|
/// </param>
|
||||||
protected Endpoint(
|
public Endpoint(
|
||||||
|
RequestDelegate requestDelegate,
|
||||||
EndpointMetadataCollection metadata,
|
EndpointMetadataCollection metadata,
|
||||||
string displayName)
|
string displayName)
|
||||||
{
|
{
|
||||||
// All are allowed to be null
|
// All are allowed to be null
|
||||||
|
RequestDelegate = requestDelegate;
|
||||||
Metadata = metadata ?? EndpointMetadataCollection.Empty;
|
Metadata = metadata ?? EndpointMetadataCollection.Empty;
|
||||||
DisplayName = displayName;
|
DisplayName = displayName;
|
||||||
}
|
}
|
||||||
|
|
@ -36,6 +39,11 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public EndpointMetadataCollection Metadata { get; }
|
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();
|
public override string ToString() => DisplayName ?? base.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Http
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A collection of arbitrary metadata associated with an endpoint.
|
/// A collection of arbitrary metadata associated with an endpoint.
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,7 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
namespace Microsoft.AspNetCore.Http.Features
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A feature interface for endpoint routing. Use <see cref="HttpContext.Features"/>
|
/// A feature interface for endpoint routing. Use <see cref="HttpContext.Features"/>
|
||||||
|
|
@ -13,21 +10,9 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public interface IEndpointFeature
|
public interface IEndpointFeature
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <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.
|
/// request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Endpoint Endpoint { get; set; }
|
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; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,7 +7,7 @@ using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Microsoft.AspNetCore.Routing.Matching;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
@ -132,15 +132,15 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
foreach (var endpoint in _endpoints)
|
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;
|
template = string.IsNullOrEmpty(template) ? "\"\"" : template;
|
||||||
sb.Append(template);
|
sb.Append(template);
|
||||||
sb.Append(", Defaults: new { ");
|
sb.Append(", Defaults: new { ");
|
||||||
sb.Append(string.Join(", ", FormatValues(matcherEndpoint.RoutePattern.Defaults)));
|
sb.Append(string.Join(", ", FormatValues(routeEndpoint.RoutePattern.Defaults)));
|
||||||
sb.Append(" }");
|
sb.Append(" }");
|
||||||
var routeValuesAddressMetadata = matcherEndpoint.Metadata.GetMetadata<IRouteValuesAddressMetadata>();
|
var routeValuesAddressMetadata = routeEndpoint.Metadata.GetMetadata<IRouteValuesAddressMetadata>();
|
||||||
sb.Append(", Route Name: ");
|
sb.Append(", Route Name: ");
|
||||||
sb.Append(routeValuesAddressMetadata?.Name);
|
sb.Append(routeValuesAddressMetadata?.Name);
|
||||||
if (routeValuesAddressMetadata?.RequiredValues != null)
|
if (routeValuesAddressMetadata?.RequiredValues != null)
|
||||||
|
|
@ -150,21 +150,21 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
sb.Append(" }");
|
sb.Append(" }");
|
||||||
}
|
}
|
||||||
sb.Append(", Order: ");
|
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)
|
if (httpMethodMetadata != null)
|
||||||
{
|
{
|
||||||
sb.Append(", Http Methods: ");
|
sb.Append(", Http Methods: ");
|
||||||
sb.Append(string.Join(", ", httpMethodMetadata.HttpMethods));
|
sb.Append(string.Join(", ", httpMethodMetadata.HttpMethods));
|
||||||
}
|
}
|
||||||
sb.Append(", Display Name: ");
|
sb.Append(", Display Name: ");
|
||||||
sb.Append(matcherEndpoint.DisplayName);
|
sb.Append(routeEndpoint.DisplayName);
|
||||||
sb.AppendLine();
|
sb.AppendLine();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sb.Append("Non-MatcherEndpoint. DisplayName:");
|
sb.Append("Non-RouteEndpoint. DisplayName:");
|
||||||
sb.AppendLine(endpoint.DisplayName);
|
sb.AppendLine(endpoint.DisplayName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.Extensions.FileProviders;
|
using Microsoft.Extensions.FileProviders;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
public DefaultLinkGenerationTemplate(
|
public DefaultLinkGenerationTemplate(
|
||||||
DefaultLinkGenerator linkGenerator,
|
DefaultLinkGenerator linkGenerator,
|
||||||
IEnumerable<MatcherEndpoint> endpoints,
|
IEnumerable<RouteEndpoint> endpoints,
|
||||||
HttpContext httpContext,
|
HttpContext httpContext,
|
||||||
RouteValueDictionary explicitValues,
|
RouteValueDictionary explicitValues,
|
||||||
RouteValueDictionary ambientValues)
|
RouteValueDictionary ambientValues)
|
||||||
|
|
@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
internal DefaultLinkGenerator LinkGenerator { get; }
|
internal DefaultLinkGenerator LinkGenerator { get; }
|
||||||
|
|
||||||
internal IEnumerable<MatcherEndpoint> Endpoints { get; }
|
internal IEnumerable<RouteEndpoint> Endpoints { get; }
|
||||||
|
|
||||||
internal HttpContext HttpContext { get; }
|
internal HttpContext HttpContext { get; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Routing.Internal;
|
using Microsoft.AspNetCore.Routing.Internal;
|
||||||
using Microsoft.AspNetCore.Routing.Matching;
|
using Microsoft.AspNetCore.Routing.Matching;
|
||||||
using Microsoft.AspNetCore.Routing.Template;
|
using Microsoft.AspNetCore.Routing.Template;
|
||||||
|
|
@ -97,7 +98,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
internal string MakeLink(
|
internal string MakeLink(
|
||||||
HttpContext httpContext,
|
HttpContext httpContext,
|
||||||
MatcherEndpoint endpoint,
|
RouteEndpoint endpoint,
|
||||||
RouteValueDictionary ambientValues,
|
RouteValueDictionary ambientValues,
|
||||||
RouteValueDictionary explicitValues,
|
RouteValueDictionary explicitValues,
|
||||||
LinkOptions options)
|
LinkOptions options)
|
||||||
|
|
@ -232,7 +233,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
private bool MatchesConstraints(
|
private bool MatchesConstraints(
|
||||||
HttpContext httpContext,
|
HttpContext httpContext,
|
||||||
MatcherEndpoint endpoint,
|
RouteEndpoint endpoint,
|
||||||
RouteValueDictionary routeValues)
|
RouteValueDictionary routeValues)
|
||||||
{
|
{
|
||||||
if (routeValues == null)
|
if (routeValues == null)
|
||||||
|
|
@ -303,16 +304,16 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
if (httpContext != null)
|
if (httpContext != null)
|
||||||
{
|
{
|
||||||
var feature = httpContext.Features.Get<IEndpointFeature>();
|
var feature = httpContext.Features.Get<IRouteValuesFeature>();
|
||||||
if (feature != null)
|
if (feature != null)
|
||||||
{
|
{
|
||||||
return feature.Values;
|
return feature.RouteValues;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new RouteValueDictionary();
|
return new RouteValueDictionary();
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<MatcherEndpoint> FindEndpoints<TAddress>(TAddress address)
|
private IEnumerable<RouteEndpoint> FindEndpoints<TAddress>(TAddress address)
|
||||||
{
|
{
|
||||||
var finder = _serviceProvider.GetRequiredService<IEndpointFinder<TAddress>>();
|
var finder = _serviceProvider.GetRequiredService<IEndpointFinder<TAddress>>();
|
||||||
var endpoints = finder.FindEndpoints(address);
|
var endpoints = finder.FindEndpoints(address);
|
||||||
|
|
@ -321,13 +322,13 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var matcherEndpoints = endpoints.OfType<MatcherEndpoint>();
|
var routeEndpoints = endpoints.OfType<RouteEndpoint>();
|
||||||
if (!matcherEndpoints.Any())
|
if (!routeEndpoints.Any())
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return matcherEndpoints;
|
return routeEndpoints;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
|
||||||
|
|
@ -3,39 +3,31 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
/// <summary>
|
public sealed class EndpointFeature : IEndpointFeature, IRouteValuesFeature, IRoutingFeature
|
||||||
/// A default implementation of <see cref="IEndpointFeature"/> and <see cref="IRoutingFeature"/>.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class EndpointFeature : IEndpointFeature, IRoutingFeature
|
|
||||||
{
|
{
|
||||||
private RouteData _routeData;
|
private RouteData _routeData;
|
||||||
private RouteValueDictionary _values;
|
private RouteValueDictionary _routeValues;
|
||||||
|
|
||||||
/// <summary>
|
/// <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.
|
/// request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Endpoint Endpoint { get; set; }
|
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>
|
/// <summary>
|
||||||
/// Gets or sets the <see cref="RouteValueDictionary"/> associated with the currrent
|
/// Gets or sets the <see cref="RouteValueDictionary"/> associated with the currrent
|
||||||
/// request.
|
/// request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public RouteValueDictionary Values
|
public RouteValueDictionary RouteValues
|
||||||
{
|
{
|
||||||
get => _values;
|
get => _routeValues;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_values = value;
|
_routeValues = value;
|
||||||
|
|
||||||
// RouteData will be created next get with new Values
|
// RouteData will be created next get with new Values
|
||||||
_routeData = null;
|
_routeData = null;
|
||||||
|
|
@ -46,7 +38,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
/// Gets or sets the <see cref="RouteData"/> for the current request.
|
/// Gets or sets the <see cref="RouteData"/> for the current request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <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>
|
/// </remarks>
|
||||||
RouteData IRoutingFeature.RouteData
|
RouteData IRoutingFeature.RouteData
|
||||||
{
|
{
|
||||||
|
|
@ -54,7 +46,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
if (_routeData == null)
|
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
|
// 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
|
// 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();
|
set => throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
@ -40,13 +41,13 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
throw new InvalidOperationException(message);
|
throw new InvalidOperationException(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (feature.Invoker != null)
|
if (feature.Endpoint?.RequestDelegate != null)
|
||||||
{
|
{
|
||||||
Log.ExecutingEndpoint(_logger, feature.Endpoint);
|
Log.ExecutingEndpoint(_logger, feature.Endpoint);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await feature.Invoker(_next)(httpContext);
|
await feature.Endpoint.RequestDelegate(httpContext);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Routing.Matching;
|
using Microsoft.AspNetCore.Routing.Matching;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
@ -54,11 +55,10 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
public async Task Invoke(HttpContext httpContext)
|
public async Task Invoke(HttpContext httpContext)
|
||||||
{
|
{
|
||||||
|
// For back-compat EndpointRouteValuesFeature implements IEndpointFeature, IRouteValuesFeature and IRoutingFeature
|
||||||
var feature = new EndpointFeature();
|
var feature = new EndpointFeature();
|
||||||
httpContext.Features.Set<IEndpointFeature>(feature);
|
|
||||||
|
|
||||||
// Back compat support for users of IRoutingFeature
|
SetEndpointFeature(httpContext, feature);
|
||||||
httpContext.Features.Set<IRoutingFeature>(feature);
|
|
||||||
|
|
||||||
// There's an inherent race condition between waiting for init and accessing the matcher
|
// 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.
|
// 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);
|
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
|
// Initialization is async to avoid blocking threads while reflection and things
|
||||||
// of that nature take place.
|
// of that nature take place.
|
||||||
//
|
//
|
||||||
|
|
@ -127,4 +139,4 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -38,8 +38,7 @@ namespace Microsoft.AspNetCore.Routing.Internal
|
||||||
var endpoints = dataSource.Endpoints;
|
var endpoints = dataSource.Endpoints;
|
||||||
for (var i = 0; i < endpoints.Count; i++)
|
for (var i = 0; i < endpoints.Count; i++)
|
||||||
{
|
{
|
||||||
var endpoint = endpoints[i] as MatcherEndpoint;
|
if (endpoints[i] is RouteEndpoint endpoint && endpoint.Metadata.GetMetadata<ISuppressMatchingMetadata>() == null)
|
||||||
if (endpoint != null && endpoint.Metadata.GetMetadata<ISuppressMatchingMetadata>() == null)
|
|
||||||
{
|
{
|
||||||
builder.AddEndpoint(endpoint);
|
builder.AddEndpoint(endpoint);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
internal readonly struct Candidate
|
internal readonly struct Candidate
|
||||||
{
|
{
|
||||||
public readonly MatcherEndpoint Endpoint;
|
public readonly RouteEndpoint Endpoint;
|
||||||
|
|
||||||
// Used to optimize out operations that modify route values.
|
// Used to optimize out operations that modify route values.
|
||||||
public readonly CandidateFlags Flags;
|
public readonly CandidateFlags Flags;
|
||||||
|
|
@ -48,7 +48,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
public readonly int Score;
|
public readonly int Score;
|
||||||
|
|
||||||
// Used in tests.
|
// Used in tests.
|
||||||
public Candidate(MatcherEndpoint endpoint)
|
public Candidate(RouteEndpoint endpoint)
|
||||||
{
|
{
|
||||||
Endpoint = endpoint;
|
Endpoint = endpoint;
|
||||||
|
|
||||||
|
|
@ -63,7 +63,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
}
|
}
|
||||||
|
|
||||||
public Candidate(
|
public Candidate(
|
||||||
MatcherEndpoint endpoint,
|
RouteEndpoint endpoint,
|
||||||
int score,
|
int score,
|
||||||
KeyValuePair<string, object>[] slots,
|
KeyValuePair<string, object>[] slots,
|
||||||
(string parameterName, int segmentIndex, int slotIndex)[] captures,
|
(string parameterName, int segmentIndex, int slotIndex)[] captures,
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
|
|
@ -35,7 +36,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="endpoints">The list of endpoints, sorted in descending priority order.</param>
|
/// <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>
|
/// <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;
|
Count = endpoints.Length;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public struct CandidateState
|
public struct CandidateState
|
||||||
{
|
{
|
||||||
internal CandidateState(MatcherEndpoint endpoint, int score)
|
internal CandidateState(RouteEndpoint endpoint, int score)
|
||||||
{
|
{
|
||||||
Endpoint = endpoint;
|
Endpoint = endpoint;
|
||||||
Score = score;
|
Score = score;
|
||||||
|
|
@ -18,12 +18,12 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="Routing.Endpoint"/>.
|
/// Gets the <see cref="Http.Endpoint"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MatcherEndpoint Endpoint { get; }
|
public RouteEndpoint Endpoint { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <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"/>.
|
/// <see cref="CandidateSet"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
|
|
@ -40,15 +40,15 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
public int Score { get; }
|
public int Score { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <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
|
/// 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>
|
/// </summary>
|
||||||
public bool IsValidCandidate { get; set; }
|
public bool IsValidCandidate { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the <see cref="RouteValueDictionary"/> associated with the
|
/// 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>
|
/// </summary>
|
||||||
public RouteValueDictionary Values { get; set; }
|
public RouteValueDictionary Values { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
|
|
@ -26,7 +27,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
// Used in tests
|
// Used in tests
|
||||||
internal Matcher CurrentMatcher => _cache.Value;
|
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);
|
return CurrentMatcher.MatchAsync(httpContext, feature);
|
||||||
}
|
}
|
||||||
|
|
@ -36,11 +37,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
var builder = _matcherBuilderFactory();
|
var builder = _matcherBuilderFactory();
|
||||||
for (var i = 0; i < endpoints.Count; i++)
|
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
|
// register other endpoint types, which are non-routable, and it's
|
||||||
// ok that we won't route to them.
|
// ok that we won't route to them.
|
||||||
var endpoint = endpoints[i] as MatcherEndpoint;
|
if (endpoints[i] is RouteEndpoint endpoint && endpoint.Metadata.GetMetadata<ISuppressMatchingMetadata>() == null)
|
||||||
if (endpoint != null && endpoint.Metadata.GetMetadata<ISuppressMatchingMetadata>() == null)
|
|
||||||
{
|
{
|
||||||
builder.AddEndpoint(endpoint);
|
builder.AddEndpoint(endpoint);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
|
|
@ -25,7 +26,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
public override Task SelectAsync(
|
public override Task SelectAsync(
|
||||||
HttpContext httpContext,
|
HttpContext httpContext,
|
||||||
IEndpointFeature feature,
|
EndpointFeature feature,
|
||||||
CandidateSet candidateSet)
|
CandidateSet candidateSet)
|
||||||
{
|
{
|
||||||
for (var i = 0; i < _selectorPolicies.Length; i++)
|
for (var i = 0; i < _selectorPolicies.Length; i++)
|
||||||
|
|
@ -33,7 +34,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
_selectorPolicies[i].Apply(httpContext, candidateSet);
|
_selectorPolicies[i].Apply(httpContext, candidateSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
MatcherEndpoint endpoint = null;
|
RouteEndpoint endpoint = null;
|
||||||
RouteValueDictionary values = null;
|
RouteValueDictionary values = null;
|
||||||
int? foundScore = null;
|
int? foundScore = null;
|
||||||
for (var i = 0; i < candidateSet.Count; i++)
|
for (var i = 0; i < candidateSet.Count; i++)
|
||||||
|
|
@ -73,8 +74,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
if (endpoint != null)
|
if (endpoint != null)
|
||||||
{
|
{
|
||||||
feature.Endpoint = endpoint;
|
feature.Endpoint = endpoint;
|
||||||
feature.Invoker = endpoint.Invoker;
|
feature.RouteValues = values;
|
||||||
feature.Values = values;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
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
|
// If we get here it's the result of an ambiguity - we're OK with this
|
||||||
// being a littler slower and more allocatey.
|
// 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++)
|
for (var i = 0; i < candidates.Count; i++)
|
||||||
{
|
{
|
||||||
ref var state = ref candidates[i];
|
ref var state = ref candidates[i];
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Routing.Patterns;
|
using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
@ -22,7 +23,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
_maxSegmentCount = maxSegmentCount;
|
_maxSegmentCount = maxSegmentCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed override Task MatchAsync(HttpContext httpContext, IEndpointFeature feature)
|
public sealed override Task MatchAsync(HttpContext httpContext, EndpointFeature feature)
|
||||||
{
|
{
|
||||||
if (httpContext == null)
|
if (httpContext == null)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
internal class DfaMatcherBuilder : MatcherBuilder
|
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 ParameterPolicyFactory _parameterPolicyFactory;
|
||||||
private readonly EndpointSelector _selector;
|
private readonly EndpointSelector _selector;
|
||||||
private readonly MatcherPolicy[] _policies;
|
private readonly MatcherPolicy[] _policies;
|
||||||
private readonly INodeBuilderPolicy[] _nodeBuilders;
|
private readonly INodeBuilderPolicy[] _nodeBuilders;
|
||||||
private readonly MatcherEndpointComparer _comparer;
|
private readonly RouteEndpointComparer _comparer;
|
||||||
|
|
||||||
public DfaMatcherBuilder(
|
public DfaMatcherBuilder(
|
||||||
ParameterPolicyFactory parameterPolicyFactory,
|
ParameterPolicyFactory parameterPolicyFactory,
|
||||||
|
|
@ -29,10 +29,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
// Taking care to use _policies, which has been sorted.
|
// Taking care to use _policies, which has been sorted.
|
||||||
_nodeBuilders = _policies.OfType<INodeBuilderPolicy>().ToArray();
|
_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);
|
_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
|
// 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
|
// this list will hold the set of items we need to process at the current
|
||||||
// stage.
|
// 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 = "/" };
|
var root = new DfaNode() { PathDepth = 0, Label = "/" };
|
||||||
|
|
||||||
|
|
@ -67,7 +67,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
for (var depth = 0; depth <= maxDepth; depth++)
|
for (var depth = 0; depth <= maxDepth; depth++)
|
||||||
{
|
{
|
||||||
// As we process items, collect the next set of items.
|
// 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++)
|
for (var i = 0; i < work.Count; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -192,7 +192,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
private RoutePatternPathSegment GetCurrentSegment(MatcherEndpoint endpoint, int depth)
|
private RoutePatternPathSegment GetCurrentSegment(RouteEndpoint endpoint, int depth)
|
||||||
{
|
{
|
||||||
if (depth < endpoint.RoutePattern.PathSegments.Count)
|
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
|
// Builds an array of candidates for a node, assigns a 'score' for each
|
||||||
// endpoint.
|
// endpoint.
|
||||||
internal Candidate[] CreateCandidates(IReadOnlyList<MatcherEndpoint> endpoints)
|
internal Candidate[] CreateCandidates(IReadOnlyList<RouteEndpoint> endpoints)
|
||||||
{
|
{
|
||||||
if (endpoints.Count == 0)
|
if (endpoints.Count == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -367,7 +367,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
}
|
}
|
||||||
|
|
||||||
// internal for tests
|
// 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 assignments = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||||
var slots = new List<KeyValuePair<string, object>>();
|
var slots = new List<KeyValuePair<string, object>>();
|
||||||
|
|
@ -481,7 +481,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
return groups.ToArray();
|
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++)
|
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
|
// 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);
|
nextWork.Add(next);
|
||||||
|
|
||||||
parent.PolicyEdges.Add(edge.State, next);
|
parent.PolicyEdges.Add(edge.State, next);
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
public DfaNode()
|
public DfaNode()
|
||||||
{
|
{
|
||||||
Literals = new Dictionary<string, DfaNode>(StringComparer.OrdinalIgnoreCase);
|
Literals = new Dictionary<string, DfaNode>(StringComparer.OrdinalIgnoreCase);
|
||||||
Matches = new List<MatcherEndpoint>();
|
Matches = new List<RouteEndpoint>();
|
||||||
PolicyEdges = new Dictionary<object, DfaNode>();
|
PolicyEdges = new Dictionary<object, DfaNode>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
// Just for diagnostics and debugging
|
// Just for diagnostics and debugging
|
||||||
public string Label { get; set; }
|
public string Label { get; set; }
|
||||||
|
|
||||||
public List<MatcherEndpoint> Matches { get; }
|
public List<RouteEndpoint> Matches { get; }
|
||||||
|
|
||||||
public Dictionary<string, DfaNode> Literals { get; }
|
public Dictionary<string, DfaNode> Literals { get; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
|
|
@ -21,13 +22,12 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
/// <param name="candidates">The <see cref="CandidateSet"/>.</param>
|
/// <param name="candidates">The <see cref="CandidateSet"/>.</param>
|
||||||
/// <returns>A <see cref="Task"/> that completes asynchronously once endpoint selection is complete.</returns>
|
/// <returns>A <see cref="Task"/> that completes asynchronously once endpoint selection is complete.</returns>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// An <see cref="EndpointSelector"/> should assign the <see cref="IEndpointFeature.Endpoint"/>,
|
/// An <see cref="EndpointSelector"/> should assign the <see cref="EndpointFeature.Endpoint"/>
|
||||||
/// <see cref="IEndpointFeature.Invoker"/>, and <see cref="IEndpointFeature.Values"/> properties
|
/// and <see cref="EndpointFeature.RouteValues"/> properties once an endpoint is selected.
|
||||||
/// once an endpoint is selected.
|
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public abstract Task SelectAsync(
|
public abstract Task SelectAsync(
|
||||||
HttpContext httpContext,
|
HttpContext httpContext,
|
||||||
IEndpointFeature feature,
|
EndpointFeature feature,
|
||||||
CandidateSet candidates);
|
CandidateSet candidates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -250,8 +250,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
private Endpoint CreateRejectionEndpoint(IEnumerable<string> httpMethods)
|
private Endpoint CreateRejectionEndpoint(IEnumerable<string> httpMethods)
|
||||||
{
|
{
|
||||||
var allow = string.Join(", ", httpMethods);
|
var allow = string.Join(", ", httpMethods);
|
||||||
return new MatcherEndpoint(
|
return new RouteEndpoint(
|
||||||
(next) => (context) =>
|
(context) =>
|
||||||
{
|
{
|
||||||
context.Response.StatusCode = 405;
|
context.Response.StatusCode = 405;
|
||||||
context.Response.Headers.Add("Allow", allow);
|
context.Response.Headers.Add("Allow", allow);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
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="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
|
||||||
/// <param name="feature">
|
/// <param name="feature">
|
||||||
/// The <see cref="IEndpointFeature"/> associated with the current request. The
|
/// 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>
|
/// <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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
internal abstract class MatcherBuilder
|
internal abstract class MatcherBuilder
|
||||||
{
|
{
|
||||||
public abstract void AddEndpoint(MatcherEndpoint endpoint);
|
public abstract void AddEndpoint(RouteEndpoint endpoint);
|
||||||
|
|
||||||
public abstract Matcher Build();
|
public abstract Matcher Build();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ using System.Diagnostics;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
// Use to sort and group MatcherEndpoints.
|
// Use to sort and group RouteEndpoints.
|
||||||
//
|
//
|
||||||
// NOTE:
|
// NOTE:
|
||||||
// When ordering endpoints, we compare the route templates as an absolute last resort.
|
// 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.
|
// IComparer implementation considers the template string as a tiebreaker.
|
||||||
// IEqualityComparer implementation does not.
|
// IEqualityComparer implementation does not.
|
||||||
// This is cool and good.
|
// 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)...
|
// Order, Precedence, (others)...
|
||||||
_comparers = new IComparer<MatcherEndpoint>[2 + policies.Length];
|
_comparers = new IComparer<RouteEndpoint>[2 + policies.Length];
|
||||||
_comparers[0] = OrderComparer.Instance;
|
_comparers[0] = OrderComparer.Instance;
|
||||||
_comparers[1] = PrecedenceComparer.Instance;
|
_comparers[1] = PrecedenceComparer.Instance;
|
||||||
for (var i = 0; i < policies.Length; i++)
|
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
|
// We don't expose this publicly, and we should never call it on
|
||||||
// a null endpoint.
|
// a null endpoint.
|
||||||
|
|
@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
return compare == 0 ? x.RoutePattern.RawText.CompareTo(y.RoutePattern.RawText) : compare;
|
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
|
// We don't expose this publicly, and we should never call it on
|
||||||
// a null endpoint.
|
// a null endpoint.
|
||||||
|
|
@ -59,14 +59,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
return CompareCore(x, y) == 0;
|
return CompareCore(x, y) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetHashCode(MatcherEndpoint obj)
|
public int GetHashCode(RouteEndpoint obj)
|
||||||
{
|
{
|
||||||
// This should not be possible to call publicly.
|
// This should not be possible to call publicly.
|
||||||
Debug.Fail("We don't expect this to be called.");
|
Debug.Fail("We don't expect this to be called.");
|
||||||
throw new System.NotImplementedException();
|
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++)
|
for (var i = 0; i < _comparers.Length; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -80,21 +80,21 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
return 0;
|
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);
|
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);
|
return x.RoutePattern.InboundPrecedence.CompareTo(y.RoutePattern.InboundPrecedence);
|
||||||
}
|
}
|
||||||
|
|
@ -7,39 +7,34 @@ using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Routing.Patterns;
|
using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents an <see cref="Endpoint"/> that can be used in URL matching or URL generation.
|
/// Represents an <see cref="Endpoint"/> that can be used in URL matching or URL generation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class MatcherEndpoint : Endpoint
|
public sealed class RouteEndpoint : Endpoint
|
||||||
{
|
{
|
||||||
internal static readonly Func<RequestDelegate, RequestDelegate> EmptyInvoker = (next) =>
|
|
||||||
{
|
|
||||||
return (context) => Task.CompletedTask;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="MatcherEndpoint"/> class.
|
/// Initializes a new instance of the <see cref="RouteEndpoint"/> class.
|
||||||
/// </summary>
|
/// </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="routePattern">The <see cref="RoutePattern"/> to use in URL matching.</param>
|
||||||
/// <param name="order">The order assigned to the endpoint.</param>
|
/// <param name="order">The order assigned to the endpoint.</param>
|
||||||
/// <param name="metadata">
|
/// <param name="metadata">
|
||||||
/// The <see cref="EndpointMetadataCollection"/> or metadata associated with the endpoint.
|
/// The <see cref="EndpointMetadataCollection"/> or metadata associated with the endpoint.
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="displayName">The informational display name of the endpoint.</param>
|
/// <param name="displayName">The informational display name of the endpoint.</param>
|
||||||
public MatcherEndpoint(
|
public RouteEndpoint(
|
||||||
Func<RequestDelegate, RequestDelegate> invoker,
|
RequestDelegate requestDelegate,
|
||||||
RoutePattern routePattern,
|
RoutePattern routePattern,
|
||||||
int order,
|
int order,
|
||||||
EndpointMetadataCollection metadata,
|
EndpointMetadataCollection metadata,
|
||||||
string displayName)
|
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)
|
if (routePattern == null)
|
||||||
|
|
@ -47,16 +42,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
throw new ArgumentNullException(nameof(routePattern));
|
throw new ArgumentNullException(nameof(routePattern));
|
||||||
}
|
}
|
||||||
|
|
||||||
Invoker = invoker;
|
|
||||||
RoutePattern = routePattern;
|
RoutePattern = routePattern;
|
||||||
Order = order;
|
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>
|
/// <summary>
|
||||||
/// Gets the order value of endpoint.
|
/// Gets the order value of endpoint.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Routing.Internal;
|
using Microsoft.AspNetCore.Routing.Internal;
|
||||||
using Microsoft.AspNetCore.Routing.Matching;
|
using Microsoft.AspNetCore.Routing.Matching;
|
||||||
using Microsoft.AspNetCore.Routing.Template;
|
using Microsoft.AspNetCore.Routing.Template;
|
||||||
|
|
@ -56,7 +57,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
return matchResults
|
return matchResults
|
||||||
.Select(matchResult => matchResult.Match)
|
.Select(matchResult => matchResult.Match)
|
||||||
.Select(match => (MatcherEndpoint)match.Entry.Data);
|
.Select(match => (RouteEndpoint)match.Entry.Data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleChange()
|
private void HandleChange()
|
||||||
|
|
@ -103,7 +104,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
var namedOutboundMatchResults = new Dictionary<string, List<OutboundMatchResult>>(
|
var namedOutboundMatchResults = new Dictionary<string, List<OutboundMatchResult>>(
|
||||||
StringComparer.OrdinalIgnoreCase);
|
StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
var endpoints = _endpointDataSource.Endpoints.OfType<MatcherEndpoint>();
|
var endpoints = _endpointDataSource.Endpoints.OfType<RouteEndpoint>();
|
||||||
foreach (var endpoint in endpoints)
|
foreach (var endpoint in endpoints)
|
||||||
{
|
{
|
||||||
// Do not consider an endpoint for link generation if the following marker metadata is on it
|
// 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);
|
return (allOutboundMatches, namedOutboundMatchResults);
|
||||||
}
|
}
|
||||||
|
|
||||||
private OutboundRouteEntry CreateOutboundRouteEntry(MatcherEndpoint endpoint)
|
private OutboundRouteEntry CreateOutboundRouteEntry(RouteEndpoint endpoint)
|
||||||
{
|
{
|
||||||
var routeValuesAddressMetadata = endpoint.Metadata.GetMetadata<IRouteValuesAddressMetadata>();
|
var routeValuesAddressMetadata = endpoint.Metadata.GetMetadata<IRouteValuesAddressMetadata>();
|
||||||
var entry = new OutboundRouteEntry()
|
var entry = new OutboundRouteEntry()
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Builder.Internal;
|
using Microsoft.AspNetCore.Builder.Internal;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Routing;
|
using Microsoft.AspNetCore.Routing;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Routing.Matching;
|
using Microsoft.AspNetCore.Routing.Matching;
|
||||||
using Microsoft.AspNetCore.Routing.Patterns;
|
using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
using Microsoft.AspNetCore.Routing.TestObjects;
|
using Microsoft.AspNetCore.Routing.TestObjects;
|
||||||
|
|
@ -146,14 +147,14 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
Assert.False(token.HasChanged);
|
Assert.False(token.HasChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MatcherEndpoint CreateEndpoint(
|
private RouteEndpoint CreateEndpoint(
|
||||||
string template,
|
string template,
|
||||||
object defaults = null,
|
object defaults = null,
|
||||||
int order = 0,
|
int order = 0,
|
||||||
string routeName = null)
|
string routeName = null)
|
||||||
{
|
{
|
||||||
return new MatcherEndpoint(
|
return new RouteEndpoint(
|
||||||
MatcherEndpoint.EmptyInvoker,
|
TestConstants.EmptyRequestDelegate,
|
||||||
RoutePatternFactory.Parse(template, defaults, parameterPolicies: null),
|
RoutePatternFactory.Parse(template, defaults, parameterPolicies: null),
|
||||||
order,
|
order,
|
||||||
EndpointMetadataCollection.Empty,
|
EndpointMetadataCollection.Empty,
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Routing.TestObjects;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
@ -16,8 +16,8 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
// Arrange & Act
|
// Arrange & Act
|
||||||
var dataSource = new DefaultEndpointDataSource(
|
var dataSource = new DefaultEndpointDataSource(
|
||||||
new TestEndpoint(EndpointMetadataCollection.Empty, "1"),
|
new Endpoint(TestConstants.EmptyRequestDelegate, EndpointMetadataCollection.Empty, "1"),
|
||||||
new TestEndpoint(EndpointMetadataCollection.Empty, "2")
|
new Endpoint(TestConstants.EmptyRequestDelegate, EndpointMetadataCollection.Empty, "2")
|
||||||
);
|
);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
@ -32,8 +32,8 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
// Arrange & Act
|
// Arrange & Act
|
||||||
var dataSource = new DefaultEndpointDataSource(new List<Endpoint>
|
var dataSource = new DefaultEndpointDataSource(new List<Endpoint>
|
||||||
{
|
{
|
||||||
new TestEndpoint(EndpointMetadataCollection.Empty, "1"),
|
new Endpoint(TestConstants.EmptyRequestDelegate, EndpointMetadataCollection.Empty, "1"),
|
||||||
new TestEndpoint(EndpointMetadataCollection.Empty, "2")
|
new Endpoint(TestConstants.EmptyRequestDelegate, EndpointMetadataCollection.Empty, "2")
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Routing.Constraints;
|
using Microsoft.AspNetCore.Routing.Constraints;
|
||||||
using Microsoft.AspNetCore.Routing.Internal;
|
using Microsoft.AspNetCore.Routing.Internal;
|
||||||
using Microsoft.AspNetCore.Routing.Matching;
|
using Microsoft.AspNetCore.Routing.Matching;
|
||||||
|
|
@ -25,7 +26,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_Success()
|
public void GetLink_Success()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}");
|
||||||
var linkGenerator = CreateLinkGenerator(endpoint);
|
var linkGenerator = CreateLinkGenerator(endpoint);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -40,7 +41,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expectedMessage = "Could not find a matching endpoint to generate a link.";
|
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);
|
var linkGenerator = CreateLinkGenerator(endpoint);
|
||||||
|
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
|
|
@ -53,7 +54,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void TryGetLink_Fail()
|
public void TryGetLink_Fail()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
|
||||||
var linkGenerator = CreateLinkGenerator(endpoint);
|
var linkGenerator = CreateLinkGenerator(endpoint);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -70,9 +71,9 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_MultipleEndpoints_Success()
|
public void GetLink_MultipleEndpoints_Success()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint1 = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}/{id?}");
|
var endpoint1 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id?}");
|
||||||
var endpoint2 = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
|
var endpoint2 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
|
||||||
var endpoint3 = EndpointFactory.CreateMatcherEndpoint("{controller}");
|
var endpoint3 = EndpointFactory.CreateRouteEndpoint("{controller}");
|
||||||
var linkGenerator = CreateLinkGenerator(endpoint1, endpoint2, endpoint3);
|
var linkGenerator = CreateLinkGenerator(endpoint1, endpoint2, endpoint3);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -86,9 +87,9 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_MultipleEndpoints_Success2()
|
public void GetLink_MultipleEndpoints_Success2()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint1 = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}/{id}");
|
var endpoint1 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{id}");
|
||||||
var endpoint2 = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
|
var endpoint2 = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
|
||||||
var endpoint3 = EndpointFactory.CreateMatcherEndpoint("{controller}");
|
var endpoint3 = EndpointFactory.CreateRouteEndpoint("{controller}");
|
||||||
var linkGenerator = CreateLinkGenerator(endpoint1, endpoint2, endpoint3);
|
var linkGenerator = CreateLinkGenerator(endpoint1, endpoint2, endpoint3);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -102,7 +103,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_EncodesIntermediate_DefaultValues()
|
public void GetLink_EncodesIntermediate_DefaultValues()
|
||||||
{
|
{
|
||||||
// Arrange
|
// 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);
|
var linkGenerator = CreateLinkGenerator(endpoint);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -118,7 +119,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_EncodesValue_OfSingleAsteriskCatchAllParameter(string routeValue, string expected)
|
public void GetLink_EncodesValue_OfSingleAsteriskCatchAllParameter(string routeValue, string expected)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}/{*path}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{*path}");
|
||||||
var linkGenerator = CreateLinkGenerator(endpoint);
|
var linkGenerator = CreateLinkGenerator(endpoint);
|
||||||
var httpContext = CreateHttpContext(ambientValues: new { controller = "Home", action = "Index" });
|
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)
|
public void GetLink_DoesNotEncodeSlashes_OfDoubleAsteriskCatchAllParameter(string routeValue, string expected)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}/{**path}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{**path}");
|
||||||
var linkGenerator = CreateLinkGenerator(endpoint);
|
var linkGenerator = CreateLinkGenerator(endpoint);
|
||||||
var httpContext = CreateHttpContext(ambientValues: new { controller = "Home", action = "Index" });
|
var httpContext = CreateHttpContext(ambientValues: new { controller = "Home", action = "Index" });
|
||||||
|
|
||||||
|
|
@ -157,7 +158,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_EncodesContentOtherThanSlashes_OfDoubleAsteriskCatchAllParameter()
|
public void GetLink_EncodesContentOtherThanSlashes_OfDoubleAsteriskCatchAllParameter()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}/{**path}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{**path}");
|
||||||
var linkGenerator = CreateLinkGenerator(endpoint);
|
var linkGenerator = CreateLinkGenerator(endpoint);
|
||||||
var httpContext = CreateHttpContext(ambientValues: new { controller = "Home", action = "Index" });
|
var httpContext = CreateHttpContext(ambientValues: new { controller = "Home", action = "Index" });
|
||||||
|
|
||||||
|
|
@ -172,7 +173,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_EncodesValues()
|
public void GetLink_EncodesValues()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
|
||||||
var linkGenerator = CreateLinkGenerator(endpoint);
|
var linkGenerator = CreateLinkGenerator(endpoint);
|
||||||
var httpContext = CreateHttpContext(ambientValues: new { controller = "Home", action = "Index" });
|
var httpContext = CreateHttpContext(ambientValues: new { controller = "Home", action = "Index" });
|
||||||
|
|
||||||
|
|
@ -187,7 +188,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_ForListOfStrings()
|
public void GetLink_ForListOfStrings()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
|
||||||
var linkGenerator = CreateLinkGenerator(endpoint);
|
var linkGenerator = CreateLinkGenerator(endpoint);
|
||||||
var context = CreateHttpContext(ambientValues: new { controller = "Home", action = "Index" });
|
var context = CreateHttpContext(ambientValues: new { controller = "Home", action = "Index" });
|
||||||
|
|
||||||
|
|
@ -202,7 +203,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_ForListOfInts()
|
public void GetLink_ForListOfInts()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
|
||||||
var linkGenerator = CreateLinkGenerator(endpoint);
|
var linkGenerator = CreateLinkGenerator(endpoint);
|
||||||
var httpContext = CreateHttpContext(ambientValues: new { controller = "Home", action = "Index" });
|
var httpContext = CreateHttpContext(ambientValues: new { controller = "Home", action = "Index" });
|
||||||
|
|
||||||
|
|
@ -217,7 +218,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_ForList_Empty()
|
public void GetLink_ForList_Empty()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
|
||||||
var linkGenerator = CreateLinkGenerator(endpoint);
|
var linkGenerator = CreateLinkGenerator(endpoint);
|
||||||
var httpContext = CreateHttpContext(ambientValues: new { controller = "Home", action = "Index" });
|
var httpContext = CreateHttpContext(ambientValues: new { controller = "Home", action = "Index" });
|
||||||
|
|
||||||
|
|
@ -232,7 +233,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_ForList_StringWorkaround()
|
public void GetLink_ForList_StringWorkaround()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
|
||||||
var linkGenerator = CreateLinkGenerator(endpoint);
|
var linkGenerator = CreateLinkGenerator(endpoint);
|
||||||
var httpContext = CreateHttpContext(ambientValues: new { controller = "Home", action = "Index" });
|
var httpContext = CreateHttpContext(ambientValues: new { controller = "Home", action = "Index" });
|
||||||
|
|
||||||
|
|
@ -249,7 +250,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_Success_AmbientValues()
|
public void GetLink_Success_AmbientValues()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
|
||||||
var linkGenerator = CreateLinkGenerator(endpoint);
|
var linkGenerator = CreateLinkGenerator(endpoint);
|
||||||
var httpContext = CreateHttpContext(ambientValues: new { controller = "Home" });
|
var httpContext = CreateHttpContext(ambientValues: new { controller = "Home" });
|
||||||
|
|
||||||
|
|
@ -264,7 +265,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_GeneratesLowercaseUrl_SetOnRouteOptions()
|
public void GetLink_GeneratesLowercaseUrl_SetOnRouteOptions()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
|
||||||
var linkGenerator = CreateLinkGenerator(new[] { endpoint }, new RouteOptions() { LowercaseUrls = true });
|
var linkGenerator = CreateLinkGenerator(new[] { endpoint }, new RouteOptions() { LowercaseUrls = true });
|
||||||
var httpContext = CreateHttpContext(ambientValues: new { controller = "Home" });
|
var httpContext = CreateHttpContext(ambientValues: new { controller = "Home" });
|
||||||
|
|
||||||
|
|
@ -279,7 +280,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_GeneratesLowercaseQueryString_SetOnRouteOptions()
|
public void GetLink_GeneratesLowercaseQueryString_SetOnRouteOptions()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
|
||||||
var linkGenerator = CreateLinkGenerator(
|
var linkGenerator = CreateLinkGenerator(
|
||||||
new[] { endpoint },
|
new[] { endpoint },
|
||||||
new RouteOptions() { LowercaseUrls = true, LowercaseQueryStrings = true });
|
new RouteOptions() { LowercaseUrls = true, LowercaseQueryStrings = true });
|
||||||
|
|
@ -298,7 +299,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_GeneratesLowercaseQueryString_OnlyIfLowercaseUrlIsTrue_SetOnRouteOptions()
|
public void GetLink_GeneratesLowercaseQueryString_OnlyIfLowercaseUrlIsTrue_SetOnRouteOptions()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
|
||||||
var linkGenerator = CreateLinkGenerator(
|
var linkGenerator = CreateLinkGenerator(
|
||||||
new[] { endpoint },
|
new[] { endpoint },
|
||||||
new RouteOptions() { LowercaseUrls = false, LowercaseQueryStrings = true });
|
new RouteOptions() { LowercaseUrls = false, LowercaseQueryStrings = true });
|
||||||
|
|
@ -317,7 +318,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_AppendsTrailingSlash_SetOnRouteOptions()
|
public void GetLink_AppendsTrailingSlash_SetOnRouteOptions()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
|
||||||
var linkGenerator = CreateLinkGenerator(
|
var linkGenerator = CreateLinkGenerator(
|
||||||
new[] { endpoint },
|
new[] { endpoint },
|
||||||
new RouteOptions() { AppendTrailingSlash = true });
|
new RouteOptions() { AppendTrailingSlash = true });
|
||||||
|
|
@ -334,7 +335,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_GeneratesLowercaseQueryStringAndTrailingSlash_SetOnRouteOptions()
|
public void GetLink_GeneratesLowercaseQueryStringAndTrailingSlash_SetOnRouteOptions()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
|
||||||
var linkGenerator = CreateLinkGenerator(
|
var linkGenerator = CreateLinkGenerator(
|
||||||
new[] { endpoint },
|
new[] { endpoint },
|
||||||
new RouteOptions() { LowercaseUrls = true, LowercaseQueryStrings = true, AppendTrailingSlash = true });
|
new RouteOptions() { LowercaseUrls = true, LowercaseQueryStrings = true, AppendTrailingSlash = true });
|
||||||
|
|
@ -353,7 +354,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_LowercaseUrlSetToTrue_OnRouteOptions_OverridenByCallsiteValue()
|
public void GetLink_LowercaseUrlSetToTrue_OnRouteOptions_OverridenByCallsiteValue()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
|
||||||
var linkGenerator = CreateLinkGenerator(
|
var linkGenerator = CreateLinkGenerator(
|
||||||
new[] { endpoint },
|
new[] { endpoint },
|
||||||
new RouteOptions() { LowercaseUrls = true });
|
new RouteOptions() { LowercaseUrls = true });
|
||||||
|
|
@ -376,7 +377,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_LowercaseUrlSetToFalse_OnRouteOptions_OverridenByCallsiteValue()
|
public void GetLink_LowercaseUrlSetToFalse_OnRouteOptions_OverridenByCallsiteValue()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
|
||||||
var linkGenerator = CreateLinkGenerator(
|
var linkGenerator = CreateLinkGenerator(
|
||||||
new[] { endpoint },
|
new[] { endpoint },
|
||||||
new RouteOptions() { LowercaseUrls = false });
|
new RouteOptions() { LowercaseUrls = false });
|
||||||
|
|
@ -399,7 +400,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_LowercaseUrlQueryStringsSetToTrue_OnRouteOptions_OverridenByCallsiteValue()
|
public void GetLink_LowercaseUrlQueryStringsSetToTrue_OnRouteOptions_OverridenByCallsiteValue()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
|
||||||
var linkGenerator = CreateLinkGenerator(
|
var linkGenerator = CreateLinkGenerator(
|
||||||
new[] { endpoint },
|
new[] { endpoint },
|
||||||
new RouteOptions() { LowercaseUrls = true, LowercaseQueryStrings = true });
|
new RouteOptions() { LowercaseUrls = true, LowercaseQueryStrings = true });
|
||||||
|
|
@ -423,7 +424,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_LowercaseUrlQueryStringsSetToFalse_OnRouteOptions_OverridenByCallsiteValue()
|
public void GetLink_LowercaseUrlQueryStringsSetToFalse_OnRouteOptions_OverridenByCallsiteValue()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
|
||||||
var linkGenerator = CreateLinkGenerator(
|
var linkGenerator = CreateLinkGenerator(
|
||||||
new[] { endpoint },
|
new[] { endpoint },
|
||||||
new RouteOptions() { LowercaseUrls = false, LowercaseQueryStrings = false });
|
new RouteOptions() { LowercaseUrls = false, LowercaseQueryStrings = false });
|
||||||
|
|
@ -447,7 +448,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_AppendTrailingSlashSetToFalse_OnRouteOptions_OverridenByCallsiteValue()
|
public void GetLink_AppendTrailingSlashSetToFalse_OnRouteOptions_OverridenByCallsiteValue()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}");
|
||||||
var linkGenerator = CreateLinkGenerator(
|
var linkGenerator = CreateLinkGenerator(
|
||||||
new[] { endpoint },
|
new[] { endpoint },
|
||||||
new RouteOptions() { AppendTrailingSlash = false });
|
new RouteOptions() { AppendTrailingSlash = false });
|
||||||
|
|
@ -470,7 +471,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void RouteGenerationRejectsConstraints()
|
public void RouteGenerationRejectsConstraints()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint = EndpointFactory.CreateRouteEndpoint(
|
||||||
"{p1}/{p2}",
|
"{p1}/{p2}",
|
||||||
defaults: new { p2 = "catchall" },
|
defaults: new { p2 = "catchall" },
|
||||||
constraints: new { p2 = "\\d{4}" });
|
constraints: new { p2 = "\\d{4}" });
|
||||||
|
|
@ -491,7 +492,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void RouteGenerationAcceptsConstraints()
|
public void RouteGenerationAcceptsConstraints()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint = EndpointFactory.CreateRouteEndpoint(
|
||||||
"{p1}/{p2}",
|
"{p1}/{p2}",
|
||||||
defaults: new { p2 = "catchall" },
|
defaults: new { p2 = "catchall" },
|
||||||
constraints: new { p2 = new RegexRouteConstraint("\\d{4}"), });
|
constraints: new { p2 = new RegexRouteConstraint("\\d{4}"), });
|
||||||
|
|
@ -513,7 +514,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void RouteWithCatchAllRejectsConstraints()
|
public void RouteWithCatchAllRejectsConstraints()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint = EndpointFactory.CreateRouteEndpoint(
|
||||||
"{p1}/{*p2}",
|
"{p1}/{*p2}",
|
||||||
defaults: new { p2 = "catchall" },
|
defaults: new { p2 = "catchall" },
|
||||||
constraints: new { p2 = new RegexRouteConstraint("\\d{4}") });
|
constraints: new { p2 = new RegexRouteConstraint("\\d{4}") });
|
||||||
|
|
@ -534,7 +535,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void RouteWithCatchAllAcceptsConstraints()
|
public void RouteWithCatchAllAcceptsConstraints()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint = EndpointFactory.CreateRouteEndpoint(
|
||||||
"{p1}/{*p2}",
|
"{p1}/{*p2}",
|
||||||
defaults: new { p2 = "catchall" },
|
defaults: new { p2 = "catchall" },
|
||||||
constraints: new { p2 = new RegexRouteConstraint("\\d{4}") });
|
constraints: new { p2 = new RegexRouteConstraint("\\d{4}") });
|
||||||
|
|
@ -567,7 +568,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
It.IsAny<RouteDirection>()))
|
It.IsAny<RouteDirection>()))
|
||||||
.Returns(true)
|
.Returns(true)
|
||||||
.Verifiable();
|
.Verifiable();
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint = EndpointFactory.CreateRouteEndpoint(
|
||||||
"{p1}/{p2}",
|
"{p1}/{p2}",
|
||||||
defaults: new { p2 = "catchall" },
|
defaults: new { p2 = "catchall" },
|
||||||
constraints: new { p2 = target.Object });
|
constraints: new { p2 = target.Object });
|
||||||
|
|
@ -593,7 +594,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var constraint = new CapturingConstraint();
|
var constraint = new CapturingConstraint();
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint = EndpointFactory.CreateRouteEndpoint(
|
||||||
template: "slug/Home/Store",
|
template: "slug/Home/Store",
|
||||||
defaults: new { controller = "Home", action = "Store" },
|
defaults: new { controller = "Home", action = "Store" },
|
||||||
constraints: new { c = constraint });
|
constraints: new { c = constraint });
|
||||||
|
|
@ -622,7 +623,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var constraint = new CapturingConstraint();
|
var constraint = new CapturingConstraint();
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint = EndpointFactory.CreateRouteEndpoint(
|
||||||
template: "slug/Home/Store",
|
template: "slug/Home/Store",
|
||||||
defaults: new { controller = "Home", action = "Store", otherthing = "17" },
|
defaults: new { controller = "Home", action = "Store", otherthing = "17" },
|
||||||
constraints: new { c = constraint });
|
constraints: new { c = constraint });
|
||||||
|
|
@ -645,7 +646,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var constraint = new CapturingConstraint();
|
var constraint = new CapturingConstraint();
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint = EndpointFactory.CreateRouteEndpoint(
|
||||||
template: "slug/{controller}/{action}",
|
template: "slug/{controller}/{action}",
|
||||||
defaults: new { action = "Index" },
|
defaults: new { action = "Index" },
|
||||||
constraints: new { c = constraint, });
|
constraints: new { c = constraint, });
|
||||||
|
|
@ -669,7 +670,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var constraint = new CapturingConstraint();
|
var constraint = new CapturingConstraint();
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint = EndpointFactory.CreateRouteEndpoint(
|
||||||
template: "slug/Home/Store",
|
template: "slug/Home/Store",
|
||||||
defaults: new { controller = "Home", action = "Store", otherthing = "17", thirdthing = "13" },
|
defaults: new { controller = "Home", action = "Store", otherthing = "17", thirdthing = "13" },
|
||||||
constraints: new { c = constraint, });
|
constraints: new { c = constraint, });
|
||||||
|
|
@ -694,7 +695,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_InlineConstraints_Success()
|
public void GetLink_InlineConstraints_Success()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint = EndpointFactory.CreateRouteEndpoint(
|
||||||
template: "Home/Index/{id:int}",
|
template: "Home/Index/{id:int}",
|
||||||
defaults: new { controller = "Home", action = "Index" },
|
defaults: new { controller = "Home", action = "Index" },
|
||||||
constraints: new { });
|
constraints: new { });
|
||||||
|
|
@ -714,7 +715,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_InlineConstraints_NonMatchingvalue()
|
public void GetLink_InlineConstraints_NonMatchingvalue()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint = EndpointFactory.CreateRouteEndpoint(
|
||||||
template: "Home/Index/{id}",
|
template: "Home/Index/{id}",
|
||||||
defaults: new { controller = "Home", action = "Index" },
|
defaults: new { controller = "Home", action = "Index" },
|
||||||
constraints: new { id = "int" });
|
constraints: new { id = "int" });
|
||||||
|
|
@ -735,7 +736,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_InlineConstraints_OptionalParameter_ValuePresent()
|
public void GetLink_InlineConstraints_OptionalParameter_ValuePresent()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint = EndpointFactory.CreateRouteEndpoint(
|
||||||
template: "Home/Index/{id:int?}",
|
template: "Home/Index/{id:int?}",
|
||||||
defaults: new { controller = "Home", action = "Index" },
|
defaults: new { controller = "Home", action = "Index" },
|
||||||
constraints: new { });
|
constraints: new { });
|
||||||
|
|
@ -753,7 +754,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_InlineConstraints_OptionalParameter_ValueNotPresent()
|
public void GetLink_InlineConstraints_OptionalParameter_ValueNotPresent()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint = EndpointFactory.CreateRouteEndpoint(
|
||||||
template: "Home/Index/{id?}",
|
template: "Home/Index/{id?}",
|
||||||
defaults: new { controller = "Home", action = "Index" },
|
defaults: new { controller = "Home", action = "Index" },
|
||||||
constraints: new { id = "int" });
|
constraints: new { id = "int" });
|
||||||
|
|
@ -771,7 +772,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_InlineConstraints_OptionalParameter_ValuePresent_ConstraintFails()
|
public void GetLink_InlineConstraints_OptionalParameter_ValuePresent_ConstraintFails()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint = EndpointFactory.CreateRouteEndpoint(
|
||||||
template: "Home/Index/{id?}",
|
template: "Home/Index/{id?}",
|
||||||
defaults: new { controller = "Home", action = "Index" },
|
defaults: new { controller = "Home", action = "Index" },
|
||||||
constraints: new { id = "int" });
|
constraints: new { id = "int" });
|
||||||
|
|
@ -792,7 +793,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_InlineConstraints_MultipleInlineConstraints()
|
public void GetLink_InlineConstraints_MultipleInlineConstraints()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint = EndpointFactory.CreateRouteEndpoint(
|
||||||
template: "Home/Index/{id:int:range(1,20)}",
|
template: "Home/Index/{id:int:range(1,20)}",
|
||||||
defaults: new { controller = "Home", action = "Index" },
|
defaults: new { controller = "Home", action = "Index" },
|
||||||
constraints: new { });
|
constraints: new { });
|
||||||
|
|
@ -812,7 +813,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_InlineConstraints_CompositeInlineConstraint_Fails()
|
public void GetLink_InlineConstraints_CompositeInlineConstraint_Fails()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint = EndpointFactory.CreateRouteEndpoint(
|
||||||
template: "Home/Index/{id:int:range(1,20)}",
|
template: "Home/Index/{id:int:range(1,20)}",
|
||||||
defaults: new { controller = "Home", action = "Index" },
|
defaults: new { controller = "Home", action = "Index" },
|
||||||
constraints: new { });
|
constraints: new { });
|
||||||
|
|
@ -834,7 +835,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var constraint = new MaxLengthRouteConstraint(20);
|
var constraint = new MaxLengthRouteConstraint(20);
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint = EndpointFactory.CreateRouteEndpoint(
|
||||||
template: "Home/Index/{name}",
|
template: "Home/Index/{name}",
|
||||||
defaults: new { controller = "Home", action = "Index" },
|
defaults: new { controller = "Home", action = "Index" },
|
||||||
constraints: new { name = constraint });
|
constraints: new { name = constraint });
|
||||||
|
|
@ -854,7 +855,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_OptionalParameter_ParameterPresentInValues()
|
public void GetLink_OptionalParameter_ParameterPresentInValues()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}/{name?}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{name?}");
|
||||||
var linkGenerator = CreateLinkGenerator(endpoint);
|
var linkGenerator = CreateLinkGenerator(endpoint);
|
||||||
var httpContext = CreateHttpContext(ambientValues: new { });
|
var httpContext = CreateHttpContext(ambientValues: new { });
|
||||||
|
|
||||||
|
|
@ -871,7 +872,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_OptionalParameter_ParameterNotPresentInValues()
|
public void GetLink_OptionalParameter_ParameterNotPresentInValues()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}/{name?}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{name?}");
|
||||||
var linkGenerator = CreateLinkGenerator(endpoint);
|
var linkGenerator = CreateLinkGenerator(endpoint);
|
||||||
var httpContext = CreateHttpContext(ambientValues: new { });
|
var httpContext = CreateHttpContext(ambientValues: new { });
|
||||||
|
|
||||||
|
|
@ -888,7 +889,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_OptionalParameter_ParameterPresentInValuesAndDefaults()
|
public void GetLink_OptionalParameter_ParameterPresentInValuesAndDefaults()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint = EndpointFactory.CreateRouteEndpoint(
|
||||||
template: "{controller}/{action}/{name}",
|
template: "{controller}/{action}/{name}",
|
||||||
defaults: new { name = "default-products" });
|
defaults: new { name = "default-products" });
|
||||||
var linkGenerator = CreateLinkGenerator(endpoint);
|
var linkGenerator = CreateLinkGenerator(endpoint);
|
||||||
|
|
@ -907,7 +908,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_OptionalParameter_ParameterNotPresentInValues_PresentInDefaults()
|
public void GetLink_OptionalParameter_ParameterNotPresentInValues_PresentInDefaults()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint = EndpointFactory.CreateRouteEndpoint(
|
||||||
template: "{controller}/{action}/{name}",
|
template: "{controller}/{action}/{name}",
|
||||||
defaults: new { name = "products" });
|
defaults: new { name = "products" });
|
||||||
var linkGenerator = CreateLinkGenerator(endpoint);
|
var linkGenerator = CreateLinkGenerator(endpoint);
|
||||||
|
|
@ -926,7 +927,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_ParameterNotPresentInTemplate_PresentInValues()
|
public void GetLink_ParameterNotPresentInTemplate_PresentInValues()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}/{name}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{name}");
|
||||||
var linkGenerator = CreateLinkGenerator(endpoint);
|
var linkGenerator = CreateLinkGenerator(endpoint);
|
||||||
var httpContext = CreateHttpContext(ambientValues: new { });
|
var httpContext = CreateHttpContext(ambientValues: new { });
|
||||||
|
|
||||||
|
|
@ -943,7 +944,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_OptionalParameter_FollowedByDotAfterSlash_ParameterPresent()
|
public void GetLink_OptionalParameter_FollowedByDotAfterSlash_ParameterPresent()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint = EndpointFactory.CreateRouteEndpoint(
|
||||||
template: "{controller}/{action}/.{name?}");
|
template: "{controller}/{action}/.{name?}");
|
||||||
var linkGenerator = CreateLinkGenerator(endpoint);
|
var linkGenerator = CreateLinkGenerator(endpoint);
|
||||||
var httpContext = CreateHttpContext(ambientValues: new { });
|
var httpContext = CreateHttpContext(ambientValues: new { });
|
||||||
|
|
@ -961,7 +962,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_OptionalParameter_FollowedByDotAfterSlash_ParameterNotPresent()
|
public void GetLink_OptionalParameter_FollowedByDotAfterSlash_ParameterNotPresent()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}/.{name?}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/.{name?}");
|
||||||
var linkGenerator = CreateLinkGenerator(endpoint);
|
var linkGenerator = CreateLinkGenerator(endpoint);
|
||||||
var httpContext = CreateHttpContext(ambientValues: new { });
|
var httpContext = CreateHttpContext(ambientValues: new { });
|
||||||
|
|
||||||
|
|
@ -976,7 +977,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_OptionalParameter_InSimpleSegment()
|
public void GetLink_OptionalParameter_InSimpleSegment()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("{controller}/{action}/{name?}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("{controller}/{action}/{name?}");
|
||||||
var linkGenerator = CreateLinkGenerator(endpoint);
|
var linkGenerator = CreateLinkGenerator(endpoint);
|
||||||
var httpContext = CreateHttpContext(ambientValues: new { });
|
var httpContext = CreateHttpContext(ambientValues: new { });
|
||||||
|
|
||||||
|
|
@ -991,7 +992,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_TwoOptionalParameters_OneValueFromAmbientValues()
|
public void GetLink_TwoOptionalParameters_OneValueFromAmbientValues()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("a/{b=15}/{c?}/{d?}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("a/{b=15}/{c?}/{d?}");
|
||||||
var linkGenerator = CreateLinkGenerator(endpoint);
|
var linkGenerator = CreateLinkGenerator(endpoint);
|
||||||
var httpContext = CreateHttpContext(ambientValues: new { c = "17" });
|
var httpContext = CreateHttpContext(ambientValues: new { c = "17" });
|
||||||
|
|
||||||
|
|
@ -1006,7 +1007,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_OptionalParameterAfterDefault_OneValueFromAmbientValues()
|
public void GetLink_OptionalParameterAfterDefault_OneValueFromAmbientValues()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("a/{b=15}/{c?}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("a/{b=15}/{c?}");
|
||||||
var linkGenerator = CreateLinkGenerator(endpoint);
|
var linkGenerator = CreateLinkGenerator(endpoint);
|
||||||
var httpContext = CreateHttpContext(ambientValues: new { c = "17" });
|
var httpContext = CreateHttpContext(ambientValues: new { c = "17" });
|
||||||
|
|
||||||
|
|
@ -1021,7 +1022,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetLink_TwoOptionalParametersAfterDefault_LastValueFromAmbientValues()
|
public void GetLink_TwoOptionalParametersAfterDefault_LastValueFromAmbientValues()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint("a/{b=15}/{c?}/{d?}");
|
var endpoint = EndpointFactory.CreateRouteEndpoint("a/{b=15}/{c?}/{d?}");
|
||||||
var linkGenerator = CreateLinkGenerator(endpoint);
|
var linkGenerator = CreateLinkGenerator(endpoint);
|
||||||
var httpContext = CreateHttpContext(ambientValues: new { d = "17" });
|
var httpContext = CreateHttpContext(ambientValues: new { d = "17" });
|
||||||
|
|
||||||
|
|
@ -1114,7 +1115,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
object defaults)
|
object defaults)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint = EndpointFactory.CreateRouteEndpoint(
|
||||||
"Products/Edit/{id}",
|
"Products/Edit/{id}",
|
||||||
requiredValues: requiredValues,
|
requiredValues: requiredValues,
|
||||||
defaults: defaults);
|
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.
|
// Verifying that discarding works in general usage case i.e when keys are not like controller, action etc.
|
||||||
|
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint = EndpointFactory.CreateRouteEndpoint(
|
||||||
"Products/Edit/{id}",
|
"Products/Edit/{id}",
|
||||||
requiredValues: new { c = "Products", a = "Edit" },
|
requiredValues: new { c = "Products", a = "Edit" },
|
||||||
defaults: 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.
|
// Verifying that discarding works in general usage case i.e when keys are not like controller, action etc.
|
||||||
|
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint = EndpointFactory.CreateRouteEndpoint(
|
||||||
"Products/Edit/{id}",
|
"Products/Edit/{id}",
|
||||||
requiredValues: new { c = "Products", a = "Edit" },
|
requiredValues: new { c = "Products", a = "Edit" },
|
||||||
defaults: 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
|
// Linking to a different action on the same controller
|
||||||
|
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint = EndpointFactory.CreateRouteEndpoint(
|
||||||
"Products/Edit/{id}",
|
"Products/Edit/{id}",
|
||||||
requiredValues: requiredValues,
|
requiredValues: requiredValues,
|
||||||
defaults: defaults);
|
defaults: defaults);
|
||||||
|
|
@ -1293,11 +1294,11 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
var services = GetBasicServices();
|
var services = GetBasicServices();
|
||||||
services.TryAddEnumerable(
|
services.TryAddEnumerable(
|
||||||
ServiceDescriptor.Singleton<IEndpointFinder<INameMetadata>, EndpointFinderByName>());
|
ServiceDescriptor.Singleton<IEndpointFinder<INameMetadata>, EndpointFinderByName>());
|
||||||
var endpoint1 = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint1 = EndpointFactory.CreateRouteEndpoint(
|
||||||
"Products/Details/{id}",
|
"Products/Details/{id}",
|
||||||
requiredValues: new { controller = "Products", action = "Details" },
|
requiredValues: new { controller = "Products", action = "Details" },
|
||||||
defaults: new { controller = "Products", action = "Details" });
|
defaults: new { controller = "Products", action = "Details" });
|
||||||
var endpoint2 = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint2 = EndpointFactory.CreateRouteEndpoint(
|
||||||
"Customers/Details/{id}",
|
"Customers/Details/{id}",
|
||||||
requiredValues: new { controller = "Customers", action = "Details" },
|
requiredValues: new { controller = "Customers", action = "Details" },
|
||||||
defaults: new { controller = "Customers", action = "Details" },
|
defaults: new { controller = "Customers", action = "Details" },
|
||||||
|
|
@ -1324,11 +1325,11 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
var services = GetBasicServices();
|
var services = GetBasicServices();
|
||||||
services.TryAddEnumerable(
|
services.TryAddEnumerable(
|
||||||
ServiceDescriptor.Singleton<IEndpointFinder<INameMetadata>, EndpointFinderByName>());
|
ServiceDescriptor.Singleton<IEndpointFinder<INameMetadata>, EndpointFinderByName>());
|
||||||
var endpoint1 = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint1 = EndpointFactory.CreateRouteEndpoint(
|
||||||
"Products/Details/{id}",
|
"Products/Details/{id}",
|
||||||
requiredValues: new { controller = "Products", action = "Details" },
|
requiredValues: new { controller = "Products", action = "Details" },
|
||||||
defaults: new { controller = "Products", action = "Details" });
|
defaults: new { controller = "Products", action = "Details" });
|
||||||
var endpoint2 = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint2 = EndpointFactory.CreateRouteEndpoint(
|
||||||
"Customers/Details/{id}",
|
"Customers/Details/{id}",
|
||||||
requiredValues: new { controller = "Customers", action = "Details" },
|
requiredValues: new { controller = "Customers", action = "Details" },
|
||||||
defaults: new { controller = "Customers", action = "Details" },
|
defaults: new { controller = "Customers", action = "Details" },
|
||||||
|
|
@ -1356,7 +1357,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetTemplate_ByRouteValues_ReturnsTemplate()
|
public void GetTemplate_ByRouteValues_ReturnsTemplate()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint1 = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint1 = EndpointFactory.CreateRouteEndpoint(
|
||||||
"Product/Edit/{id}",
|
"Product/Edit/{id}",
|
||||||
requiredValues: new { controller = "Product", action = "Edit", area = (string)null, page = (string)null },
|
requiredValues: new { controller = "Product", action = "Edit", area = (string)null, page = (string)null },
|
||||||
defaults: 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()
|
public void GetTemplate_ByRouteName_ReturnsTemplate()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint1 = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint1 = EndpointFactory.CreateRouteEndpoint(
|
||||||
"Product/Edit/{id}",
|
"Product/Edit/{id}",
|
||||||
defaults: new { controller = "Product", action = "Edit", area = (string)null, page = (string)null },
|
defaults: new { controller = "Product", action = "Edit", area = (string)null, page = (string)null },
|
||||||
metadata: new RouteValuesAddressMetadata(
|
metadata: new RouteValuesAddressMetadata(
|
||||||
|
|
@ -1403,13 +1404,13 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void GetTemplate_ByRouteName_ReturnsTemplate_WithMultipleEndpoints()
|
public void GetTemplate_ByRouteName_ReturnsTemplate_WithMultipleEndpoints()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint1 = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint1 = EndpointFactory.CreateRouteEndpoint(
|
||||||
"Product/Edit/{id}",
|
"Product/Edit/{id}",
|
||||||
defaults: new { controller = "Product", action = "Edit", area = (string)null, page = (string)null },
|
defaults: new { controller = "Product", action = "Edit", area = (string)null, page = (string)null },
|
||||||
metadata: new RouteValuesAddressMetadata(
|
metadata: new RouteValuesAddressMetadata(
|
||||||
"default",
|
"default",
|
||||||
new RouteValueDictionary(new { controller = "Product", action = "Edit", area = (string)null, page = (string)null })));
|
new RouteValueDictionary(new { controller = "Product", action = "Edit", area = (string)null, page = (string)null })));
|
||||||
var endpoint2 = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint2 = EndpointFactory.CreateRouteEndpoint(
|
||||||
"Product/Details/{id}",
|
"Product/Details/{id}",
|
||||||
defaults: new { controller = "Product", action = "Edit", area = (string)null, page = (string)null },
|
defaults: new { controller = "Product", action = "Edit", area = (string)null, page = (string)null },
|
||||||
metadata: new RouteValuesAddressMetadata(
|
metadata: new RouteValuesAddressMetadata(
|
||||||
|
|
@ -1436,11 +1437,11 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
var services = GetBasicServices();
|
var services = GetBasicServices();
|
||||||
services.TryAddEnumerable(
|
services.TryAddEnumerable(
|
||||||
ServiceDescriptor.Singleton<IEndpointFinder<INameMetadata>, EndpointFinderByName>());
|
ServiceDescriptor.Singleton<IEndpointFinder<INameMetadata>, EndpointFinderByName>());
|
||||||
var endpoint1 = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint1 = EndpointFactory.CreateRouteEndpoint(
|
||||||
"Product/Edit/{id}",
|
"Product/Edit/{id}",
|
||||||
requiredValues: new { controller = "Product", action = "Edit", area = (string)null, page = (string)null },
|
requiredValues: new { controller = "Product", action = "Edit", area = (string)null, page = (string)null },
|
||||||
defaults: 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}",
|
"Customers/Details/{id}",
|
||||||
requiredValues: new { controller = "Customers", action = "Details" },
|
requiredValues: new { controller = "Customers", action = "Details" },
|
||||||
defaults: new { controller = "Customers", action = "Details" },
|
defaults: new { controller = "Customers", action = "Details" },
|
||||||
|
|
@ -1466,11 +1467,11 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
var services = GetBasicServices();
|
var services = GetBasicServices();
|
||||||
services.TryAddEnumerable(
|
services.TryAddEnumerable(
|
||||||
ServiceDescriptor.Singleton<IEndpointFinder<INameMetadata>, EndpointFinderByName>());
|
ServiceDescriptor.Singleton<IEndpointFinder<INameMetadata>, EndpointFinderByName>());
|
||||||
var endpoint1 = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint1 = EndpointFactory.CreateRouteEndpoint(
|
||||||
"Product/Edit/{id}",
|
"Product/Edit/{id}",
|
||||||
requiredValues: new { controller = "Product", action = "Edit", area = (string)null, page = (string)null },
|
requiredValues: new { controller = "Product", action = "Edit", area = (string)null, page = (string)null },
|
||||||
defaults: 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}",
|
"Customers/Details/{id}",
|
||||||
requiredValues: new { controller = "Customers", action = "Details" },
|
requiredValues: new { controller = "Customers", action = "Details" },
|
||||||
defaults: new { controller = "Customers", action = "Details" },
|
defaults: new { controller = "Customers", action = "Details" },
|
||||||
|
|
@ -1500,7 +1501,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public void MakeUrl_GeneratesLink_WithExtraRouteValues()
|
public void MakeUrl_GeneratesLink_WithExtraRouteValues()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint1 = EndpointFactory.CreateMatcherEndpoint(
|
var endpoint1 = EndpointFactory.CreateRouteEndpoint(
|
||||||
"Product/Edit/{id}",
|
"Product/Edit/{id}",
|
||||||
requiredValues: new { controller = "Product", action = "Edit", area = (string)null, page = (string)null },
|
requiredValues: new { controller = "Product", action = "Edit", area = (string)null, page = (string)null },
|
||||||
defaults: 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)
|
private HttpContext CreateHttpContext(object ambientValues)
|
||||||
{
|
{
|
||||||
var httpContext = new DefaultHttpContext();
|
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;
|
return httpContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Routing.Matching;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Routing.Patterns;
|
using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
@ -10,7 +10,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
internal static class EndpointFactory
|
internal static class EndpointFactory
|
||||||
{
|
{
|
||||||
public static MatcherEndpoint CreateMatcherEndpoint(
|
public static RouteEndpoint CreateRouteEndpoint(
|
||||||
string template,
|
string template,
|
||||||
object defaults = null,
|
object defaults = null,
|
||||||
object constraints = null,
|
object constraints = null,
|
||||||
|
|
@ -25,8 +25,8 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
d.Add(new RouteValuesAddressMetadata(null, new RouteValueDictionary(requiredValues)));
|
d.Add(new RouteValuesAddressMetadata(null, new RouteValueDictionary(requiredValues)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MatcherEndpoint(
|
return new RouteEndpoint(
|
||||||
MatcherEndpoint.EmptyInvoker,
|
TestConstants.EmptyRequestDelegate,
|
||||||
RoutePatternFactory.Parse(template, defaults, constraints),
|
RoutePatternFactory.Parse(template, defaults, constraints),
|
||||||
order,
|
order,
|
||||||
new EndpointMetadataCollection(d),
|
new EndpointMetadataCollection(d),
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Routing.Matching;
|
using Microsoft.AspNetCore.Routing.Matching;
|
||||||
using Microsoft.AspNetCore.Routing.Patterns;
|
using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
@ -18,8 +19,8 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
var feature = new EndpointFeature()
|
var feature = new EndpointFeature()
|
||||||
{
|
{
|
||||||
Endpoint = new MatcherEndpoint(
|
Endpoint = new RouteEndpoint(
|
||||||
MatcherEndpoint.EmptyInvoker,
|
TestConstants.EmptyRequestDelegate,
|
||||||
RoutePatternFactory.Parse("/"),
|
RoutePatternFactory.Parse("/"),
|
||||||
0,
|
0,
|
||||||
new EndpointMetadataCollection(new DataTokensMetadata(expected)),
|
new EndpointMetadataCollection(new DataTokensMetadata(expected)),
|
||||||
|
|
@ -40,8 +41,8 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
// Arrange
|
// Arrange
|
||||||
var feature = new EndpointFeature()
|
var feature = new EndpointFeature()
|
||||||
{
|
{
|
||||||
Endpoint = new MatcherEndpoint(
|
Endpoint = new RouteEndpoint(
|
||||||
MatcherEndpoint.EmptyInvoker,
|
TestConstants.EmptyRequestDelegate,
|
||||||
RoutePatternFactory.Parse("/"),
|
RoutePatternFactory.Parse("/"),
|
||||||
0,
|
0,
|
||||||
new EndpointMetadataCollection(),
|
new EndpointMetadataCollection(),
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Routing.TestObjects;
|
using Microsoft.AspNetCore.Routing.TestObjects;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
|
|
@ -19,8 +20,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public async Task Invoke_OnCall_SetsEndpointFeature()
|
public async Task Invoke_OnCall_SetsEndpointFeature()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var httpContext = new DefaultHttpContext();
|
var httpContext = CreateHttpContext();
|
||||||
httpContext.RequestServices = new TestServiceProvider();
|
|
||||||
|
|
||||||
var middleware = CreateMiddleware();
|
var middleware = CreateMiddleware();
|
||||||
|
|
||||||
|
|
@ -43,8 +43,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
TestSink.EnableWithTypeName<EndpointRoutingMiddleware>);
|
TestSink.EnableWithTypeName<EndpointRoutingMiddleware>);
|
||||||
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
||||||
|
|
||||||
var httpContext = new DefaultHttpContext();
|
var httpContext = CreateHttpContext();
|
||||||
httpContext.RequestServices = new TestServiceProvider();
|
|
||||||
|
|
||||||
var logger = new Logger<EndpointRoutingMiddleware>(loggerFactory);
|
var logger = new Logger<EndpointRoutingMiddleware>(loggerFactory);
|
||||||
var middleware = CreateMiddleware(logger);
|
var middleware = CreateMiddleware(logger);
|
||||||
|
|
@ -62,8 +61,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public async Task Invoke_BackCompatGetRouteValue_ValueUsedFromEndpointFeature()
|
public async Task Invoke_BackCompatGetRouteValue_ValueUsedFromEndpointFeature()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var httpContext = new DefaultHttpContext();
|
var httpContext = CreateHttpContext();
|
||||||
httpContext.RequestServices = new TestServiceProvider();
|
|
||||||
|
|
||||||
var middleware = CreateMiddleware();
|
var middleware = CreateMiddleware();
|
||||||
|
|
||||||
|
|
@ -71,7 +69,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
await middleware.Invoke(httpContext);
|
await middleware.Invoke(httpContext);
|
||||||
var routeData = httpContext.GetRouteData();
|
var routeData = httpContext.GetRouteData();
|
||||||
var routeValue = httpContext.GetRouteValue("controller");
|
var routeValue = httpContext.GetRouteValue("controller");
|
||||||
var endpointFeature = httpContext.Features.Get<IEndpointFeature>();
|
var routeValuesFeature = httpContext.Features.Get<IRouteValuesFeature>();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.NotNull(routeData);
|
Assert.NotNull(routeData);
|
||||||
|
|
@ -79,15 +77,14 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// changing route data value is reflected in endpoint feature values
|
// changing route data value is reflected in endpoint feature values
|
||||||
routeData.Values["testKey"] = "testValue";
|
routeData.Values["testKey"] = "testValue";
|
||||||
Assert.Equal("testValue", endpointFeature.Values["testKey"]);
|
Assert.Equal("testValue", routeValuesFeature.RouteValues["testKey"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Invoke_BackCompatGetDataTokens_ValueUsedFromEndpointMetadata()
|
public async Task Invoke_BackCompatGetDataTokens_ValueUsedFromEndpointMetadata()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var httpContext = new DefaultHttpContext();
|
var httpContext = CreateHttpContext();
|
||||||
httpContext.RequestServices = new TestServiceProvider();
|
|
||||||
|
|
||||||
var middleware = CreateMiddleware();
|
var middleware = CreateMiddleware();
|
||||||
|
|
||||||
|
|
@ -95,7 +92,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
await middleware.Invoke(httpContext);
|
await middleware.Invoke(httpContext);
|
||||||
var routeData = httpContext.GetRouteData();
|
var routeData = httpContext.GetRouteData();
|
||||||
var routeValue = httpContext.GetRouteValue("controller");
|
var routeValue = httpContext.GetRouteValue("controller");
|
||||||
var endpointFeature = httpContext.Features.Get<IEndpointFeature>();
|
var routeValuesFeature = httpContext.Features.Get<IRouteValuesFeature>();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.NotNull(routeData);
|
Assert.NotNull(routeData);
|
||||||
|
|
@ -103,7 +100,20 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
// changing route data value is reflected in endpoint feature values
|
// changing route data value is reflected in endpoint feature values
|
||||||
routeData.Values["testKey"] = "testValue";
|
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)
|
private EndpointRoutingMiddleware CreateMiddleware(Logger<EndpointRoutingMiddleware> logger = null)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
|
|
@ -19,7 +20,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
Matchers = matchers;
|
Matchers = matchers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task MatchAsync(HttpContext httpContext, IEndpointFeature feature)
|
public override Task MatchAsync(HttpContext httpContext, EndpointFeature feature)
|
||||||
{
|
{
|
||||||
if (httpContext == null)
|
if (httpContext == null)
|
||||||
{
|
{
|
||||||
|
|
@ -37,7 +38,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
if (Matchers[i].TryMatch(path))
|
if (Matchers[i].TryMatch(path))
|
||||||
{
|
{
|
||||||
feature.Endpoint = Matchers[i].Endpoint;
|
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 sealed class InnerMatcher : Matcher
|
||||||
{
|
{
|
||||||
public readonly MatcherEndpoint Endpoint;
|
public readonly RouteEndpoint Endpoint;
|
||||||
|
|
||||||
private readonly string[] _segments;
|
private readonly string[] _segments;
|
||||||
private readonly Candidate[] _candidates;
|
private readonly Candidate[] _candidates;
|
||||||
|
|
||||||
public InnerMatcher(string[] segments, MatcherEndpoint endpoint)
|
public InnerMatcher(string[] segments, RouteEndpoint endpoint)
|
||||||
{
|
{
|
||||||
_segments = segments;
|
_segments = segments;
|
||||||
Endpoint = endpoint;
|
Endpoint = endpoint;
|
||||||
|
|
@ -120,12 +121,12 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
return Array.Empty<Candidate>();
|
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))
|
if (TryMatch(httpContext.Request.Path.Value))
|
||||||
{
|
{
|
||||||
feature.Endpoint = Endpoint;
|
feature.Endpoint = Endpoint;
|
||||||
feature.Values = new RouteValueDictionary();
|
feature.RouteValues = new RouteValueDictionary();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,9 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
internal class BarebonesMatcherBuilder : MatcherBuilder
|
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);
|
_endpoints.Add(endpoint);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override Matcher CreateMatcher(params MatcherEndpoint[] endpoints)
|
internal override Matcher CreateMatcher(params RouteEndpoint[] endpoints)
|
||||||
{
|
{
|
||||||
var builder = new BarebonesMatcherBuilder();
|
var builder = new BarebonesMatcherBuilder();
|
||||||
for (int i = 0; i < endpoints.Length; i++)
|
for (int i = 0; i < endpoints.Length; i++)
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Routing.Patterns;
|
using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
@ -24,7 +25,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
public void Create_CreatesCandidateSet(int count)
|
public void Create_CreatesCandidateSet(int count)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoints = new MatcherEndpoint[count];
|
var endpoints = new RouteEndpoint[count];
|
||||||
for (var i = 0; i < endpoints.Length; i++)
|
for (var i = 0; i < endpoints.Length; i++)
|
||||||
{
|
{
|
||||||
endpoints[i] = CreateEndpoint($"/{i}");
|
endpoints[i] = CreateEndpoint($"/{i}");
|
||||||
|
|
@ -60,7 +61,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
public void Create_CreatesCandidateSet_TestConstructor(int count)
|
public void Create_CreatesCandidateSet_TestConstructor(int count)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoints = new MatcherEndpoint[count];
|
var endpoints = new RouteEndpoint[count];
|
||||||
for (var i = 0; i < endpoints.Length; i++)
|
for (var i = 0; i < endpoints.Length; i++)
|
||||||
{
|
{
|
||||||
endpoints[i] = CreateEndpoint($"/{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(
|
return new RouteEndpoint(
|
||||||
MatcherEndpoint.EmptyInvoker,
|
TestConstants.EmptyRequestDelegate,
|
||||||
RoutePatternFactory.Parse(template),
|
RoutePatternFactory.Parse(template),
|
||||||
0,
|
0,
|
||||||
EndpointMetadataCollection.Empty,
|
EndpointMetadataCollection.Empty,
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Routing.Patterns;
|
using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
using Microsoft.AspNetCore.Routing.TestObjects;
|
using Microsoft.AspNetCore.Routing.TestObjects;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
@ -34,8 +35,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
var dataSource = new DynamicEndpointDataSource();
|
var dataSource = new DynamicEndpointDataSource();
|
||||||
var matcher = new DataSourceDependentMatcher(dataSource, TestMatcherBuilder.Create);
|
var matcher = new DataSourceDependentMatcher(dataSource, TestMatcherBuilder.Create);
|
||||||
|
|
||||||
var endpoint = new MatcherEndpoint(
|
var endpoint = new RouteEndpoint(
|
||||||
MatcherEndpoint.EmptyInvoker,
|
TestConstants.EmptyRequestDelegate,
|
||||||
RoutePatternFactory.Parse("a/b/c"),
|
RoutePatternFactory.Parse("a/b/c"),
|
||||||
0,
|
0,
|
||||||
EndpointMetadataCollection.Empty,
|
EndpointMetadataCollection.Empty,
|
||||||
|
|
@ -52,11 +53,11 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Matcher_Ignores_NonMatcherEndpoint()
|
public void Matcher_Ignores_NonRouteEndpoint()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var dataSource = new DynamicEndpointDataSource();
|
var dataSource = new DynamicEndpointDataSource();
|
||||||
var endpoint = new TestEndpoint(EndpointMetadataCollection.Empty, "test");
|
var endpoint = new Endpoint(TestConstants.EmptyRequestDelegate, EndpointMetadataCollection.Empty, "test");
|
||||||
dataSource.AddEndpoint(endpoint);
|
dataSource.AddEndpoint(endpoint);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -72,8 +73,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var dataSource = new DynamicEndpointDataSource();
|
var dataSource = new DynamicEndpointDataSource();
|
||||||
var endpoint = new MatcherEndpoint(
|
var endpoint = new RouteEndpoint(
|
||||||
MatcherEndpoint.EmptyInvoker,
|
TestConstants.EmptyRequestDelegate,
|
||||||
RoutePatternFactory.Parse("/"),
|
RoutePatternFactory.Parse("/"),
|
||||||
0,
|
0,
|
||||||
new EndpointMetadataCollection(new SuppressMatchingMetadata()),
|
new EndpointMetadataCollection(new SuppressMatchingMetadata()),
|
||||||
|
|
@ -116,9 +117,9 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
public static Func<MatcherBuilder> Create = () => new TestMatcherBuilder();
|
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);
|
Endpoints.Add(endpoint);
|
||||||
}
|
}
|
||||||
|
|
@ -131,9 +132,9 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
private class TestMatcher : Matcher
|
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();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Routing.Patterns;
|
using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
@ -15,7 +16,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
public async Task SelectAsync_NoCandidates_DoesNothing()
|
public async Task SelectAsync_NoCandidates_DoesNothing()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoints = new MatcherEndpoint[] { };
|
var endpoints = new RouteEndpoint[] { };
|
||||||
var scores = new int[] { };
|
var scores = new int[] { };
|
||||||
var candidateSet = CreateCandidateSet(endpoints, scores);
|
var candidateSet = CreateCandidateSet(endpoints, scores);
|
||||||
|
|
||||||
|
|
@ -33,7 +34,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
public async Task SelectAsync_NoValidCandidates_DoesNothing()
|
public async Task SelectAsync_NoValidCandidates_DoesNothing()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoints = new MatcherEndpoint[] { CreateEndpoint("/test"), };
|
var endpoints = new RouteEndpoint[] { CreateEndpoint("/test"), };
|
||||||
var scores = new int[] { 0, };
|
var scores = new int[] { 0, };
|
||||||
var candidateSet = CreateCandidateSet(endpoints, scores);
|
var candidateSet = CreateCandidateSet(endpoints, scores);
|
||||||
|
|
||||||
|
|
@ -48,14 +49,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Null(feature.Endpoint);
|
Assert.Null(feature.Endpoint);
|
||||||
Assert.Null(feature.Values);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task SelectAsync_SingleCandidate_ChoosesCandidate()
|
public async Task SelectAsync_SingleCandidate_ChoosesCandidate()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoints = new MatcherEndpoint[] { CreateEndpoint("/test"), };
|
var endpoints = new RouteEndpoint[] { CreateEndpoint("/test"), };
|
||||||
var scores = new int[] { 0, };
|
var scores = new int[] { 0, };
|
||||||
var candidateSet = CreateCandidateSet(endpoints, scores);
|
var candidateSet = CreateCandidateSet(endpoints, scores);
|
||||||
|
|
||||||
|
|
@ -70,18 +70,16 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Same(endpoints[0], feature.Endpoint);
|
Assert.Same(endpoints[0], feature.Endpoint);
|
||||||
Assert.Same(endpoints[0].Invoker, feature.Invoker);
|
|
||||||
Assert.NotNull(feature.Values);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task SelectAsync_SingleValidCandidate_ChoosesCandidate()
|
public async Task SelectAsync_SingleValidCandidate_ChoosesCandidate()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoints = new MatcherEndpoint[] { CreateEndpoint("/test1"), CreateEndpoint("/test2"), };
|
var endpoints = new RouteEndpoint[] { CreateEndpoint("/test1"), CreateEndpoint("/test2"), };
|
||||||
var scores = new int[] { 0, 0 };
|
var scores = new int[] { 0, 0 };
|
||||||
var candidateSet = CreateCandidateSet(endpoints, scores);
|
var candidateSet = CreateCandidateSet(endpoints, scores);
|
||||||
|
|
||||||
candidateSet[0].IsValidCandidate = false;
|
candidateSet[0].IsValidCandidate = false;
|
||||||
candidateSet[1].IsValidCandidate = true;
|
candidateSet[1].IsValidCandidate = true;
|
||||||
|
|
||||||
|
|
@ -99,7 +97,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
public async Task SelectAsync_SingleValidCandidateInGroup_ChoosesCandidate()
|
public async Task SelectAsync_SingleValidCandidateInGroup_ChoosesCandidate()
|
||||||
{
|
{
|
||||||
// Arrange
|
// 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 scores = new int[] { 0, 0, 1 };
|
||||||
var candidateSet = CreateCandidateSet(endpoints, scores);
|
var candidateSet = CreateCandidateSet(endpoints, scores);
|
||||||
|
|
||||||
|
|
@ -121,7 +119,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
public async Task SelectAsync_ManyGroupsLastCandidate_ChoosesCandidate()
|
public async Task SelectAsync_ManyGroupsLastCandidate_ChoosesCandidate()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoints = new MatcherEndpoint[]
|
var endpoints = new RouteEndpoint[]
|
||||||
{
|
{
|
||||||
CreateEndpoint("/test1"),
|
CreateEndpoint("/test1"),
|
||||||
CreateEndpoint("/test2"),
|
CreateEndpoint("/test2"),
|
||||||
|
|
@ -152,7 +150,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
public async Task SelectAsync_MultipleValidCandidatesInGroup_ReportsAmbiguity()
|
public async Task SelectAsync_MultipleValidCandidatesInGroup_ReportsAmbiguity()
|
||||||
{
|
{
|
||||||
// Arrange
|
// 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 scores = new int[] { 0, 1, 1 };
|
||||||
var candidateSet = CreateCandidateSet(endpoints, scores);
|
var candidateSet = CreateCandidateSet(endpoints, scores);
|
||||||
|
|
||||||
|
|
@ -179,7 +177,7 @@ test: /test3", ex.Message);
|
||||||
public async Task SelectAsync_RunsEndpointSelectorPolicies()
|
public async Task SelectAsync_RunsEndpointSelectorPolicies()
|
||||||
{
|
{
|
||||||
// Arrange
|
// 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 scores = new int[] { 0, 0, 1 };
|
||||||
var candidateSet = CreateCandidateSet(endpoints, scores);
|
var candidateSet = CreateCandidateSet(endpoints, scores);
|
||||||
|
|
||||||
|
|
@ -206,22 +204,27 @@ test: /test3", ex.Message);
|
||||||
Assert.Same(endpoints[2], feature.Endpoint);
|
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(
|
return new RouteEndpoint(
|
||||||
MatcherEndpoint.EmptyInvoker,
|
TestConstants.EmptyRequestDelegate,
|
||||||
RoutePatternFactory.Parse(template),
|
RoutePatternFactory.Parse(template),
|
||||||
0,
|
0,
|
||||||
EndpointMetadataCollection.Empty,
|
EndpointMetadataCollection.Empty,
|
||||||
$"test: {template}");
|
$"test: {template}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CandidateSet CreateCandidateSet(MatcherEndpoint[] endpoints, int[] scores)
|
private static CandidateSet CreateCandidateSet(RouteEndpoint[] endpoints, int[] scores)
|
||||||
{
|
{
|
||||||
return new CandidateSet(endpoints, scores);
|
return new CandidateSet(endpoints, scores);
|
||||||
}
|
}
|
||||||
|
|
@ -231,4 +234,4 @@ test: /test3", ex.Message);
|
||||||
return new DefaultEndpointSelector(policies);
|
return new DefaultEndpointSelector(policies);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Routing.Constraints;
|
using Microsoft.AspNetCore.Routing.Constraints;
|
||||||
using Microsoft.AspNetCore.Routing.Patterns;
|
using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
@ -876,14 +877,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
policies);
|
policies);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MatcherEndpoint CreateEndpoint(
|
private RouteEndpoint CreateEndpoint(
|
||||||
string template,
|
string template,
|
||||||
object defaults = null,
|
object defaults = null,
|
||||||
object constraints = null,
|
object constraints = null,
|
||||||
params object[] metadata)
|
params object[] metadata)
|
||||||
{
|
{
|
||||||
return new MatcherEndpoint(
|
return new RouteEndpoint(
|
||||||
MatcherEndpoint.EmptyInvoker,
|
TestConstants.EmptyRequestDelegate,
|
||||||
RoutePatternFactory.Parse(template, new RouteValueDictionary(defaults), new RouteValueDictionary(constraints)),
|
RoutePatternFactory.Parse(template, new RouteValueDictionary(defaults), new RouteValueDictionary(constraints)),
|
||||||
0,
|
0,
|
||||||
new EndpointMetadataCollection(metadata),
|
new EndpointMetadataCollection(metadata),
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// 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()
|
var services = new ServiceCollection()
|
||||||
.AddLogging()
|
.AddLogging()
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Routing.Patterns;
|
using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
|
@ -15,10 +16,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
// so we're reusing the services here.
|
// so we're reusing the services here.
|
||||||
public class DfaMatcherTest
|
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(
|
return new RouteEndpoint(
|
||||||
MatcherEndpoint.EmptyInvoker,
|
TestConstants.EmptyRequestDelegate,
|
||||||
RoutePatternFactory.Parse(template, defaults, parameterPolicies: null),
|
RoutePatternFactory.Parse(template, defaults, parameterPolicies: null),
|
||||||
order,
|
order,
|
||||||
metadata ?? EndpointMetadataCollection.Empty,
|
metadata ?? EndpointMetadataCollection.Empty,
|
||||||
|
|
@ -54,11 +55,9 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
var matcher = CreateDfaMatcher(endpointDataSource);
|
var matcher = CreateDfaMatcher(endpointDataSource);
|
||||||
|
|
||||||
var httpContext = new DefaultHttpContext();
|
var (httpContext, endpointFeature) = CreateHttpContext();
|
||||||
httpContext.Request.Path = "/1";
|
httpContext.Request.Path = "/1";
|
||||||
|
|
||||||
var endpointFeature = new EndpointFeature();
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await matcher.MatchAsync(httpContext, endpointFeature);
|
await matcher.MatchAsync(httpContext, endpointFeature);
|
||||||
|
|
||||||
|
|
@ -77,11 +76,9 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
var matcher = CreateDfaMatcher(endpointDataSource);
|
var matcher = CreateDfaMatcher(endpointDataSource);
|
||||||
|
|
||||||
var httpContext = new DefaultHttpContext();
|
var (httpContext, endpointFeature) = CreateHttpContext();
|
||||||
httpContext.Request.Path = "/One";
|
httpContext.Request.Path = "/One";
|
||||||
|
|
||||||
var endpointFeature = new EndpointFeature();
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await matcher.MatchAsync(httpContext, endpointFeature);
|
await matcher.MatchAsync(httpContext, endpointFeature);
|
||||||
|
|
||||||
|
|
@ -104,11 +101,9 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
var matcher = CreateDfaMatcher(endpointDataSource);
|
var matcher = CreateDfaMatcher(endpointDataSource);
|
||||||
|
|
||||||
var httpContext = new DefaultHttpContext();
|
var (httpContext, endpointFeature) = CreateHttpContext();
|
||||||
httpContext.Request.Path = "/Teams";
|
httpContext.Request.Path = "/Teams";
|
||||||
|
|
||||||
var endpointFeature = new EndpointFeature();
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await matcher.MatchAsync(httpContext, endpointFeature);
|
await matcher.MatchAsync(httpContext, endpointFeature);
|
||||||
|
|
||||||
|
|
@ -125,7 +120,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
var endpointSelector = new Mock<EndpointSelector>();
|
var endpointSelector = new Mock<EndpointSelector>();
|
||||||
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) =>
|
.Callback<HttpContext, IEndpointFeature, CandidateSet>((c, f, cs) =>
|
||||||
{
|
{
|
||||||
Assert.Equal(2, cs.Count);
|
Assert.Equal(2, cs.Count);
|
||||||
|
|
@ -152,16 +147,25 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
var matcher = CreateDfaMatcher(endpointDataSource, endpointSelector.Object);
|
var matcher = CreateDfaMatcher(endpointDataSource, endpointSelector.Object);
|
||||||
|
|
||||||
var httpContext = new DefaultHttpContext();
|
var (httpContext, endpointFeature) = CreateHttpContext();
|
||||||
httpContext.Request.Path = "/Teams";
|
httpContext.Request.Path = "/Teams";
|
||||||
|
|
||||||
var endpointFeature = new EndpointFeature();
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await matcher.MatchAsync(httpContext, endpointFeature);
|
await matcher.MatchAsync(httpContext, endpointFeature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(endpoint2, endpointFeature.Endpoint);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNetCore.Routing.TestObjects;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
@ -13,8 +13,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
public void Compare_EndpointWithMetadata_MoreSpecific()
|
public void Compare_EndpointWithMetadata_MoreSpecific()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint1 = new TestEndpoint(new EndpointMetadataCollection(new object[] { new TestMetadata(), }), "test1");
|
var endpoint1 = new Endpoint(TestConstants.EmptyRequestDelegate, new EndpointMetadataCollection(new object[] { new TestMetadata(), }), "test1");
|
||||||
var endpoint2 = new TestEndpoint(new EndpointMetadataCollection(new object[] { }), "test2");
|
var endpoint2 = new Endpoint(TestConstants.EmptyRequestDelegate, new EndpointMetadataCollection(new object[] { }), "test2");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = EndpointMetadataComparer<TestMetadata>.Default.Compare(endpoint1, endpoint2);
|
var result = EndpointMetadataComparer<TestMetadata>.Default.Compare(endpoint1, endpoint2);
|
||||||
|
|
@ -27,8 +27,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
public void Compare_EndpointWithMetadata_ReverseOrder_MoreSpecific()
|
public void Compare_EndpointWithMetadata_ReverseOrder_MoreSpecific()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint1 = new TestEndpoint(new EndpointMetadataCollection(new object[] { }), "test1");
|
var endpoint1 = new Endpoint(TestConstants.EmptyRequestDelegate, new EndpointMetadataCollection(new object[] { }), "test1");
|
||||||
var endpoint2 = new TestEndpoint(new EndpointMetadataCollection(new object[] { new TestMetadata(), }), "test2");
|
var endpoint2 = new Endpoint(TestConstants.EmptyRequestDelegate, new EndpointMetadataCollection(new object[] { new TestMetadata(), }), "test2");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = EndpointMetadataComparer<TestMetadata>.Default.Compare(endpoint1, endpoint2);
|
var result = EndpointMetadataComparer<TestMetadata>.Default.Compare(endpoint1, endpoint2);
|
||||||
|
|
@ -41,8 +41,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
public void Compare_BothEndpointsWithMetadata_Equal()
|
public void Compare_BothEndpointsWithMetadata_Equal()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint1 = new TestEndpoint(new EndpointMetadataCollection(new object[] { new TestMetadata(), }), "test1");
|
var endpoint1 = new Endpoint(TestConstants.EmptyRequestDelegate, new EndpointMetadataCollection(new object[] { new TestMetadata(), }), "test1");
|
||||||
var endpoint2 = new TestEndpoint(new EndpointMetadataCollection(new object[] { new TestMetadata(), }), "test2");
|
var endpoint2 = new Endpoint(TestConstants.EmptyRequestDelegate, new EndpointMetadataCollection(new object[] { new TestMetadata(), }), "test2");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = EndpointMetadataComparer<TestMetadata>.Default.Compare(endpoint1, endpoint2);
|
var result = EndpointMetadataComparer<TestMetadata>.Default.Compare(endpoint1, endpoint2);
|
||||||
|
|
@ -55,8 +55,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
public void Compare_BothEndpointsWithoutMetadata_Equal()
|
public void Compare_BothEndpointsWithoutMetadata_Equal()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint1 = new TestEndpoint(new EndpointMetadataCollection(new object[] { }), "test1");
|
var endpoint1 = new Endpoint(TestConstants.EmptyRequestDelegate, new EndpointMetadataCollection(new object[] { }), "test1");
|
||||||
var endpoint2 = new TestEndpoint(new EndpointMetadataCollection(new object[] { }), "test2");
|
var endpoint2 = new Endpoint(TestConstants.EmptyRequestDelegate, new EndpointMetadataCollection(new object[] { }), "test2");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = EndpointMetadataComparer<TestMetadata>.Default.Compare(endpoint1, endpoint2);
|
var result = EndpointMetadataComparer<TestMetadata>.Default.Compare(endpoint1, endpoint2);
|
||||||
|
|
@ -69,8 +69,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
public void Sort_EndpointWithMetadata_FirstInList()
|
public void Sort_EndpointWithMetadata_FirstInList()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var endpoint1 = new TestEndpoint(new EndpointMetadataCollection(new object[] { new TestMetadata(), }), "test1");
|
var endpoint1 = new Endpoint(TestConstants.EmptyRequestDelegate, new EndpointMetadataCollection(new object[] { new TestMetadata(), }), "test1");
|
||||||
var endpoint2 = new TestEndpoint(new EndpointMetadataCollection(new object[] { }), "test2");
|
var endpoint2 = new Endpoint(TestConstants.EmptyRequestDelegate, new EndpointMetadataCollection(new object[] { }), "test2");
|
||||||
|
|
||||||
var list = new List<Endpoint>() { endpoint2, endpoint1, };
|
var list = new List<Endpoint>() { endpoint2, endpoint1, };
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint, keys, values);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint, keys, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint, new { b = "17", c = "18", });
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint, new { b = "17", c = "18", });
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// 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]
|
[Theory]
|
||||||
|
|
@ -89,7 +89,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertNotMatch(feature);
|
MatcherAssert.AssertNotMatch(feature, httpContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
@ -121,7 +121,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint, keys, values);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint, keys, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
@ -144,7 +144,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertNotMatch(feature);
|
MatcherAssert.AssertNotMatch(feature, httpContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
@ -168,7 +168,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// 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
|
// 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);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertNotMatch(feature);
|
MatcherAssert.AssertNotMatch(feature, httpContext);
|
||||||
|
|
||||||
// Need to access these to prevent a warning from the xUnit analyzer.
|
// 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.
|
// 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);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint, keys, values);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint, keys, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
@ -243,7 +243,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertNotMatch(feature);
|
MatcherAssert.AssertNotMatch(feature, httpContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
@ -272,7 +272,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint, keys, values);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint, keys, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
@ -298,7 +298,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// 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!
|
// 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);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint, keys, values);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint, keys, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
@ -353,7 +353,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, expected, ignoreValues: true);
|
MatcherAssert.AssertMatch(feature, httpContext, expected, ignoreValues: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
@ -387,7 +387,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, expected, ignoreValues: true);
|
MatcherAssert.AssertMatch(feature, httpContext, expected, ignoreValues: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
@ -440,7 +440,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, expected, ignoreValues: true);
|
MatcherAssert.AssertMatch(feature, httpContext, expected, ignoreValues: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -5,6 +5,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Routing.Patterns;
|
using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
@ -28,7 +29,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -44,7 +45,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -60,7 +61,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -94,7 +95,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -110,7 +111,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -126,7 +127,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -142,7 +143,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact] // This matches because the endpoint accepts OPTIONS
|
[Fact] // This matches because the endpoint accepts OPTIONS
|
||||||
|
|
@ -158,7 +159,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -174,7 +175,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact] // When all of the candidates handles specific verbs, use a 405 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);
|
Assert.Same(HttpMethodMatcherPolicy.Http405EndpointDisplayName, feature.Endpoint.DisplayName);
|
||||||
|
|
||||||
// Invoke the endpoint
|
// Invoke the endpoint
|
||||||
await feature.Invoker((c) => Task.CompletedTask)(httpContext);
|
await feature.Endpoint.RequestDelegate(httpContext);
|
||||||
Assert.Equal(405, httpContext.Response.StatusCode);
|
Assert.Equal(405, httpContext.Response.StatusCode);
|
||||||
Assert.Equal("DELETE, GET, PUT", httpContext.Response.Headers["Allow"]);
|
Assert.Equal("DELETE, GET, PUT", httpContext.Response.Headers["Allow"]);
|
||||||
}
|
}
|
||||||
|
|
@ -216,7 +217,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertNotMatch(feature);
|
MatcherAssert.AssertNotMatch(feature, httpContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact] // When one of the candidates handles all verbs, dont use a 405 endpoint
|
[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);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertNotMatch(feature);
|
MatcherAssert.AssertNotMatch(feature, httpContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -250,7 +251,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint1);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint1);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -267,7 +268,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint1);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint1);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact] // The non-http-method-specific endpoint is part of the same candidate set
|
[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);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// 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()
|
var services = new ServiceCollection()
|
||||||
.AddOptions()
|
.AddOptions()
|
||||||
|
|
@ -304,7 +305,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
return builder.Build();
|
return builder.Build();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static (HttpContext httpContext, IEndpointFeature feature) CreateContext(
|
internal static (HttpContext httpContext, EndpointFeature feature) CreateContext(
|
||||||
string path,
|
string path,
|
||||||
string httpMethod,
|
string httpMethod,
|
||||||
bool corsPreflight = false)
|
bool corsPreflight = false)
|
||||||
|
|
@ -321,10 +322,11 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
var feature = new EndpointFeature();
|
var feature = new EndpointFeature();
|
||||||
httpContext.Features.Set<IEndpointFeature>(feature);
|
httpContext.Features.Set<IEndpointFeature>(feature);
|
||||||
|
httpContext.Features.Set<IRouteValuesFeature>(feature);
|
||||||
|
|
||||||
return (httpContext, feature);
|
return (httpContext, feature);
|
||||||
}
|
}
|
||||||
internal static MatcherEndpoint CreateEndpoint(
|
internal static RouteEndpoint CreateEndpoint(
|
||||||
string template,
|
string template,
|
||||||
object defaults = null,
|
object defaults = null,
|
||||||
object constraints = null,
|
object constraints = null,
|
||||||
|
|
@ -339,15 +341,15 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
}
|
}
|
||||||
|
|
||||||
var displayName = "endpoint: " + template + " " + string.Join(", ", httpMethods ?? new[] { "(any)" });
|
var displayName = "endpoint: " + template + " " + string.Join(", ", httpMethods ?? new[] { "(any)" });
|
||||||
return new MatcherEndpoint(
|
return new RouteEndpoint(
|
||||||
MatcherEndpoint.EmptyInvoker,
|
TestConstants.EmptyRequestDelegate,
|
||||||
RoutePatternFactory.Parse(template, defaults, constraints),
|
RoutePatternFactory.Parse(template, defaults, constraints),
|
||||||
order,
|
order,
|
||||||
new EndpointMetadataCollection(metadata),
|
new EndpointMetadataCollection(metadata),
|
||||||
displayName);
|
displayName);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal (Matcher matcher, MatcherEndpoint endpoint) CreateMatcher(string template)
|
internal (Matcher matcher, RouteEndpoint endpoint) CreateMatcher(string template)
|
||||||
{
|
{
|
||||||
var endpoint = CreateEndpoint(template);
|
var endpoint = CreateEndpoint(template);
|
||||||
return (CreateMatcher(endpoint), endpoint);
|
return (CreateMatcher(endpoint), endpoint);
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Routing.Patterns;
|
using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using static Microsoft.AspNetCore.Routing.Matching.HttpMethodMatcherPolicy;
|
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>();
|
var metadata = new List<object>();
|
||||||
if (httpMethodMetadata != null)
|
if (httpMethodMetadata != null)
|
||||||
|
|
@ -284,8 +285,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
metadata.Add(httpMethodMetadata);
|
metadata.Add(httpMethodMetadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MatcherEndpoint(
|
return new RouteEndpoint(
|
||||||
MatcherEndpoint.EmptyInvoker,
|
TestConstants.EmptyRequestDelegate,
|
||||||
RoutePatternFactory.Parse(template),
|
RoutePatternFactory.Parse(template),
|
||||||
0,
|
0,
|
||||||
new EndpointMetadataCollection(metadata),
|
new EndpointMetadataCollection(metadata),
|
||||||
|
|
|
||||||
|
|
@ -4,28 +4,30 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Xunit.Sdk;
|
using Xunit.Sdk;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
internal static class MatcherAssert
|
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>();
|
keys = keys ?? Array.Empty<string>();
|
||||||
values = values ?? 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));
|
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(
|
public static void AssertMatch(
|
||||||
IEndpointFeature feature,
|
EndpointFeature feature,
|
||||||
|
HttpContext context,
|
||||||
Endpoint expected,
|
Endpoint expected,
|
||||||
RouteValueDictionary values,
|
RouteValueDictionary values,
|
||||||
bool ignoreValues = false)
|
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.");
|
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))
|
if (!object.ReferenceEquals(expected, feature.Endpoint))
|
||||||
{
|
{
|
||||||
throw new XunitException(
|
throw new XunitException(
|
||||||
$"Was expected to match '{expected.DisplayName}' but matched " +
|
$"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)
|
if (!ignoreValues)
|
||||||
{
|
{
|
||||||
// Note: this comparison is intended for unit testing, and is stricter than necessary to make tests
|
// 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.
|
// more precise. Route value comparisons in product code are more flexible than a simple .Equals.
|
||||||
if (values.Count != feature.Values.Count ||
|
if (values.Count != actualValues.Count ||
|
||||||
!values.OrderBy(kvp => kvp.Key).SequenceEqual(feature.Values.OrderBy(kvp => kvp.Key)))
|
!values.OrderBy(kvp => kvp.Key).SequenceEqual(actualValues.OrderBy(kvp => kvp.Key)))
|
||||||
{
|
{
|
||||||
throw new XunitException(
|
throw new XunitException(
|
||||||
$"Was expected to match '{expected.DisplayName}' with values {FormatRouteValues(values)} but matched " +
|
$"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)
|
if (feature.Endpoint != null)
|
||||||
{
|
{
|
||||||
throw new XunitException(
|
throw new XunitException(
|
||||||
$"Was expected not to match '{feature.Endpoint.DisplayName}' " +
|
$"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}'")) + "}";
|
return "{" + string.Join(", ", values.Select(kvp => $"{kvp.Key} = '{kvp.Value}'")) + "}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -47,7 +47,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some matchers will optimize for the ASCII case
|
// Some matchers will optimize for the ASCII case
|
||||||
|
|
@ -81,7 +81,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Matchers should operate on the decoded representation - a matcher that calls
|
// 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);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
@ -119,7 +119,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertNotMatch(feature);
|
MatcherAssert.AssertNotMatch(feature, httpContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
@ -136,7 +136,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Matchers do their own 'splitting' of the path into segments, so including
|
// 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);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Matchers do their own 'splitting' of the path into segments, so including
|
// 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);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertNotMatch(feature);
|
MatcherAssert.AssertNotMatch(feature, httpContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -205,7 +205,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint, values);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -220,7 +220,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint, values);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -235,7 +235,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint, values);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -255,7 +255,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint, values);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
@ -273,7 +273,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertNotMatch(feature);
|
MatcherAssert.AssertNotMatch(feature, httpContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
@ -294,7 +294,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertMatch(feature, endpoint, keys, values);
|
MatcherAssert.AssertMatch(feature, httpContext, endpoint, keys, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
@ -323,7 +323,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
MatcherAssert.AssertNotMatch(feature);
|
MatcherAssert.AssertNotMatch(feature, httpContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Routing.Patterns;
|
using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
|
@ -11,9 +12,9 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
public abstract partial class MatcherConformanceTest
|
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();
|
var httpContext = new DefaultHttpContext();
|
||||||
httpContext.Request.Method = "TEST";
|
httpContext.Request.Method = "TEST";
|
||||||
|
|
@ -22,6 +23,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
var feature = new EndpointFeature();
|
var feature = new EndpointFeature();
|
||||||
httpContext.Features.Set<IEndpointFeature>(feature);
|
httpContext.Features.Set<IEndpointFeature>(feature);
|
||||||
|
httpContext.Features.Set<IRouteValuesFeature>(feature);
|
||||||
|
|
||||||
return (httpContext, feature);
|
return (httpContext, feature);
|
||||||
}
|
}
|
||||||
|
|
@ -34,21 +36,21 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
return services.BuildServiceProvider();
|
return services.BuildServiceProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static MatcherEndpoint CreateEndpoint(
|
internal static RouteEndpoint CreateEndpoint(
|
||||||
string template,
|
string template,
|
||||||
object defaults = null,
|
object defaults = null,
|
||||||
object constraints = null,
|
object constraints = null,
|
||||||
int? order = null)
|
int? order = null)
|
||||||
{
|
{
|
||||||
return new MatcherEndpoint(
|
return new RouteEndpoint(
|
||||||
MatcherEndpoint.EmptyInvoker,
|
TestConstants.EmptyRequestDelegate,
|
||||||
RoutePatternFactory.Parse(template, defaults, constraints),
|
RoutePatternFactory.Parse(template, defaults, constraints),
|
||||||
order ?? 0,
|
order ?? 0,
|
||||||
EndpointMetadataCollection.Empty,
|
EndpointMetadataCollection.Empty,
|
||||||
"endpoint: " + template);
|
"endpoint: " + template);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal (Matcher matcher, MatcherEndpoint endpoint) CreateMatcher(string template)
|
internal (Matcher matcher, RouteEndpoint endpoint) CreateMatcher(string template)
|
||||||
{
|
{
|
||||||
var endpoint = CreateEndpoint(template);
|
var endpoint = CreateEndpoint(template);
|
||||||
return (CreateMatcher(endpoint), endpoint);
|
return (CreateMatcher(endpoint), endpoint);
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,13 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Routing.Patterns;
|
using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
public class MatcherEndpointComparerTest
|
public class RouteEndpointComparerTest
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Compare_PrefersOrder_IfDifferent()
|
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());
|
var endpoint7 = CreateEndpoint("/bar{baz}", order: 0, new TestMetadata1(), new TestMetadata2());
|
||||||
|
|
||||||
// Endpoints listed in reverse of the desired order.
|
// 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());
|
var comparer = CreateComparer(new TestMetadata1Policy(), new TestMetadata2Policy());
|
||||||
|
|
||||||
|
|
@ -217,19 +218,19 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
e => Assert.Same(endpoint7, e));
|
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(
|
return new RouteEndpoint(
|
||||||
MatcherEndpoint.EmptyInvoker,
|
TestConstants.EmptyRequestDelegate,
|
||||||
RoutePatternFactory.Parse(template),
|
RoutePatternFactory.Parse(template),
|
||||||
order,
|
order,
|
||||||
new EndpointMetadataCollection(metadata),
|
new EndpointMetadataCollection(metadata),
|
||||||
"test: " + template);
|
"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
|
private class TestMetadata1
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
|
|
@ -17,7 +18,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
_inner = inner;
|
_inner = inner;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async override Task MatchAsync(HttpContext httpContext, IEndpointFeature feature)
|
public async override Task MatchAsync(HttpContext httpContext, EndpointFeature feature)
|
||||||
{
|
{
|
||||||
if (httpContext == null)
|
if (httpContext == null)
|
||||||
{
|
{
|
||||||
|
|
@ -34,7 +35,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
if (context.Handler != null)
|
if (context.Handler != null)
|
||||||
{
|
{
|
||||||
feature.Values = context.RouteData.Values;
|
feature.RouteValues = context.RouteData.Values;
|
||||||
await context.Handler(httpContext);
|
await context.Handler(httpContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Routing.Patterns;
|
using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
|
|
@ -13,15 +14,15 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
internal class RouteMatcherBuilder : MatcherBuilder
|
internal class RouteMatcherBuilder : MatcherBuilder
|
||||||
{
|
{
|
||||||
private readonly IInlineConstraintResolver _constraintResolver;
|
private readonly IInlineConstraintResolver _constraintResolver;
|
||||||
private readonly List<MatcherEndpoint> _endpoints;
|
private readonly List<RouteEndpoint> _endpoints;
|
||||||
|
|
||||||
public RouteMatcherBuilder()
|
public RouteMatcherBuilder()
|
||||||
{
|
{
|
||||||
_constraintResolver = new DefaultInlineConstraintResolver(Options.Create(new RouteOptions()));
|
_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);
|
_endpoints.Add(endpoint);
|
||||||
}
|
}
|
||||||
|
|
@ -73,10 +74,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
private class SelectorRouter : IRouter
|
private class SelectorRouter : IRouter
|
||||||
{
|
{
|
||||||
private readonly EndpointSelector _selector;
|
private readonly EndpointSelector _selector;
|
||||||
private readonly MatcherEndpoint[] _candidates;
|
private readonly RouteEndpoint[] _candidates;
|
||||||
private readonly int[] _scores;
|
private readonly int[] _scores;
|
||||||
|
|
||||||
public SelectorRouter(EndpointSelector selector, MatcherEndpoint[] candidates)
|
public SelectorRouter(EndpointSelector selector, RouteEndpoint[] candidates)
|
||||||
{
|
{
|
||||||
_selector = selector;
|
_selector = selector;
|
||||||
_candidates = candidates;
|
_candidates = candidates;
|
||||||
|
|
@ -91,7 +92,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
public async Task RouteAsync(RouteContext context)
|
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
|
// This is needed due to a quirk of our tests - they reuse the endpoint feature
|
||||||
// across requests.
|
// across requests.
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
public class RouteMatcherConformanceTest : FullFeaturedMatcherConformanceTest
|
public class RouteMatcherConformanceTest : FullFeaturedMatcherConformanceTest
|
||||||
{
|
{
|
||||||
internal override Matcher CreateMatcher(params MatcherEndpoint[] endpoints)
|
internal override Matcher CreateMatcher(params RouteEndpoint[] endpoints)
|
||||||
{
|
{
|
||||||
var builder = new RouteMatcherBuilder();
|
var builder = new RouteMatcherBuilder();
|
||||||
for (int i = 0; i < endpoints.Length; i++)
|
for (int i = 0; i < endpoints.Length; i++)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Routing.Tree;
|
using Microsoft.AspNetCore.Routing.Tree;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
@ -18,7 +19,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
_inner = inner;
|
_inner = inner;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async override Task MatchAsync(HttpContext httpContext, IEndpointFeature feature)
|
public async override Task MatchAsync(HttpContext httpContext, EndpointFeature feature)
|
||||||
{
|
{
|
||||||
if (httpContext == null)
|
if (httpContext == null)
|
||||||
{
|
{
|
||||||
|
|
@ -35,7 +36,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
if (context.Handler != null)
|
if (context.Handler != null)
|
||||||
{
|
{
|
||||||
feature.Values = context.RouteData.Values;
|
feature.RouteValues = context.RouteData.Values;
|
||||||
await context.Handler(httpContext);
|
await context.Handler(httpContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Routing.Internal;
|
using Microsoft.AspNetCore.Routing.Internal;
|
||||||
using Microsoft.AspNetCore.Routing.Template;
|
using Microsoft.AspNetCore.Routing.Template;
|
||||||
using Microsoft.AspNetCore.Routing.Tree;
|
using Microsoft.AspNetCore.Routing.Tree;
|
||||||
|
|
@ -16,14 +17,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
internal class TreeRouterMatcherBuilder : MatcherBuilder
|
internal class TreeRouterMatcherBuilder : MatcherBuilder
|
||||||
{
|
{
|
||||||
private readonly List<MatcherEndpoint> _endpoints;
|
private readonly List<RouteEndpoint> _endpoints;
|
||||||
|
|
||||||
public TreeRouterMatcherBuilder()
|
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);
|
_endpoints.Add(endpoint);
|
||||||
}
|
}
|
||||||
|
|
@ -48,7 +49,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
var candidates = group.ToArray();
|
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
|
// as well as those specified with a literal. We need to separate those
|
||||||
// for legacy cases.
|
// for legacy cases.
|
||||||
var endpoint = group.First();
|
var endpoint = group.First();
|
||||||
|
|
@ -75,10 +76,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
private class SelectorRouter : IRouter
|
private class SelectorRouter : IRouter
|
||||||
{
|
{
|
||||||
private readonly EndpointSelector _selector;
|
private readonly EndpointSelector _selector;
|
||||||
private readonly MatcherEndpoint[] _candidates;
|
private readonly RouteEndpoint[] _candidates;
|
||||||
private readonly int[] _scores;
|
private readonly int[] _scores;
|
||||||
|
|
||||||
public SelectorRouter(EndpointSelector selector, MatcherEndpoint[] candidates)
|
public SelectorRouter(EndpointSelector selector, RouteEndpoint[] candidates)
|
||||||
{
|
{
|
||||||
_selector = selector;
|
_selector = selector;
|
||||||
_candidates = candidates;
|
_candidates = candidates;
|
||||||
|
|
@ -93,7 +94,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
public async Task RouteAsync(RouteContext context)
|
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.
|
// This is needed due to a quirk of our tests - they reuse the endpoint feature.
|
||||||
feature.Endpoint = null;
|
feature.Endpoint = null;
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override Matcher CreateMatcher(params MatcherEndpoint[] endpoints)
|
internal override Matcher CreateMatcher(params RouteEndpoint[] endpoints)
|
||||||
{
|
{
|
||||||
var builder = new TreeRouterMatcherBuilder();
|
var builder = new TreeRouterMatcherBuilder();
|
||||||
for (var i = 0; i < endpoints.Length; i++)
|
for (var i = 0; i < endpoints.Length; i++)
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Routing.Internal;
|
using Microsoft.AspNetCore.Routing.Internal;
|
||||||
using Microsoft.AspNetCore.Routing.Matching;
|
using Microsoft.AspNetCore.Routing.Matching;
|
||||||
using Microsoft.AspNetCore.Routing.Patterns;
|
using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
|
|
@ -34,7 +35,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
Assert.NotNull(finder.NamedMatches);
|
Assert.NotNull(finder.NamedMatches);
|
||||||
Assert.True(finder.NamedMatches.TryGetValue("named", out var namedMatches));
|
Assert.True(finder.NamedMatches.TryGetValue("named", out var namedMatches));
|
||||||
var namedMatch = Assert.Single(namedMatches);
|
var namedMatch = Assert.Single(namedMatches);
|
||||||
var actual = Assert.IsType<MatcherEndpoint>(namedMatch.Match.Entry.Data);
|
var actual = Assert.IsType<RouteEndpoint>(namedMatch.Match.Entry.Data);
|
||||||
Assert.Same(endpoint2, actual);
|
Assert.Same(endpoint2, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -55,8 +56,8 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
Assert.NotNull(finder.NamedMatches);
|
Assert.NotNull(finder.NamedMatches);
|
||||||
Assert.True(finder.NamedMatches.TryGetValue("named", out var namedMatches));
|
Assert.True(finder.NamedMatches.TryGetValue("named", out var namedMatches));
|
||||||
Assert.Equal(2, namedMatches.Count);
|
Assert.Equal(2, namedMatches.Count);
|
||||||
Assert.Same(endpoint2, Assert.IsType<MatcherEndpoint>(namedMatches[0].Match.Entry.Data));
|
Assert.Same(endpoint2, Assert.IsType<RouteEndpoint>(namedMatches[0].Match.Entry.Data));
|
||||||
Assert.Same(endpoint3, Assert.IsType<MatcherEndpoint>(namedMatches[1].Match.Entry.Data));
|
Assert.Same(endpoint3, Assert.IsType<RouteEndpoint>(namedMatches[1].Match.Entry.Data));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -76,8 +77,8 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
Assert.NotNull(finder.NamedMatches);
|
Assert.NotNull(finder.NamedMatches);
|
||||||
Assert.True(finder.NamedMatches.TryGetValue("named", out var namedMatches));
|
Assert.True(finder.NamedMatches.TryGetValue("named", out var namedMatches));
|
||||||
Assert.Equal(2, namedMatches.Count);
|
Assert.Equal(2, namedMatches.Count);
|
||||||
Assert.Same(endpoint2, Assert.IsType<MatcherEndpoint>(namedMatches[0].Match.Entry.Data));
|
Assert.Same(endpoint2, Assert.IsType<RouteEndpoint>(namedMatches[0].Match.Entry.Data));
|
||||||
Assert.Same(endpoint3, Assert.IsType<MatcherEndpoint>(namedMatches[1].Match.Entry.Data));
|
Assert.Same(endpoint3, Assert.IsType<RouteEndpoint>(namedMatches[1].Match.Entry.Data));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -97,7 +98,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
// Assert 1
|
// Assert 1
|
||||||
Assert.NotNull(finder.AllMatches);
|
Assert.NotNull(finder.AllMatches);
|
||||||
var match = Assert.Single(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);
|
Assert.Same(endpoint1, actual);
|
||||||
|
|
||||||
// Arrange 2
|
// Arrange 2
|
||||||
|
|
@ -127,22 +128,22 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
finder.AllMatches,
|
finder.AllMatches,
|
||||||
(m) =>
|
(m) =>
|
||||||
{
|
{
|
||||||
actual = Assert.IsType<MatcherEndpoint>(m.Entry.Data);
|
actual = Assert.IsType<RouteEndpoint>(m.Entry.Data);
|
||||||
Assert.Same(endpoint1, actual);
|
Assert.Same(endpoint1, actual);
|
||||||
},
|
},
|
||||||
(m) =>
|
(m) =>
|
||||||
{
|
{
|
||||||
actual = Assert.IsType<MatcherEndpoint>(m.Entry.Data);
|
actual = Assert.IsType<RouteEndpoint>(m.Entry.Data);
|
||||||
Assert.Same(endpoint2, actual);
|
Assert.Same(endpoint2, actual);
|
||||||
},
|
},
|
||||||
(m) =>
|
(m) =>
|
||||||
{
|
{
|
||||||
actual = Assert.IsType<MatcherEndpoint>(m.Entry.Data);
|
actual = Assert.IsType<RouteEndpoint>(m.Entry.Data);
|
||||||
Assert.Same(endpoint3, actual);
|
Assert.Same(endpoint3, actual);
|
||||||
},
|
},
|
||||||
(m) =>
|
(m) =>
|
||||||
{
|
{
|
||||||
actual = Assert.IsType<MatcherEndpoint>(m.Entry.Data);
|
actual = Assert.IsType<RouteEndpoint>(m.Entry.Data);
|
||||||
Assert.Same(endpoint4, actual);
|
Assert.Same(endpoint4, actual);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -231,7 +232,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
objectPool);
|
objectPool);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MatcherEndpoint CreateEndpoint(
|
private RouteEndpoint CreateEndpoint(
|
||||||
string template,
|
string template,
|
||||||
object defaults = null,
|
object defaults = null,
|
||||||
object requiredValues = null,
|
object requiredValues = null,
|
||||||
|
|
@ -249,8 +250,8 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
metadataCollection = new EndpointMetadataCollection(metadata);
|
metadataCollection = new EndpointMetadataCollection(metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MatcherEndpoint(
|
return new RouteEndpoint(
|
||||||
MatcherEndpoint.EmptyInvoker,
|
TestConstants.EmptyRequestDelegate,
|
||||||
RoutePatternFactory.Parse(template, defaults, parameterPolicies: null),
|
RoutePatternFactory.Parse(template, defaults, parameterPolicies: null),
|
||||||
order,
|
order,
|
||||||
metadataCollection,
|
metadataCollection,
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.TestObjects
|
namespace Microsoft.AspNetCore.Routing.TestObjects
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Routing.Matching;
|
using Microsoft.AspNetCore.Routing.Matching;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.TestObjects
|
namespace Microsoft.AspNetCore.Routing.TestObjects
|
||||||
|
|
@ -16,12 +17,12 @@ namespace Microsoft.AspNetCore.Routing.TestObjects
|
||||||
_isHandled = isHandled;
|
_isHandled = isHandled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task MatchAsync(HttpContext httpContext, IEndpointFeature feature)
|
public override Task MatchAsync(HttpContext httpContext, EndpointFeature feature)
|
||||||
{
|
{
|
||||||
if (_isHandled)
|
if (_isHandled)
|
||||||
{
|
{
|
||||||
feature.Values = new RouteValueDictionary(new { controller = "Home", action = "Index" });
|
feature.RouteValues = new RouteValueDictionary(new { controller = "Home", action = "Index" });
|
||||||
feature.Endpoint = new TestEndpoint(EndpointMetadataCollection.Empty, "Test endpoint");
|
feature.Endpoint = new Endpoint(TestConstants.EmptyRequestDelegate, EndpointMetadataCollection.Empty, "Test endpoint");
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue