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