Remove EndpointSelectorContext

This commit is contained in:
Ryan Nowak 2019-05-07 20:40:41 -07:00 committed by Ryan Nowak
parent a36a57df65
commit 0a1d68b8f3
45 changed files with 514 additions and 654 deletions

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
@ -87,7 +87,7 @@ namespace Microsoft.AspNetCore.Http.Abstractions.Tests
// Assert // Assert
var feature = context.Features.Get<IEndpointFeature>(); var feature = context.Features.Get<IEndpointFeature>();
Assert.NotNull(feature); Assert.NotNull(feature);
Assert.Equal(endpoint, feature.Endpoint); Assert.Equal(endpoint, context.GetEndpoint());
} }
[Fact] [Fact]
@ -109,7 +109,7 @@ namespace Microsoft.AspNetCore.Http.Abstractions.Tests
// Assert // Assert
var feature = context.Features.Get<IEndpointFeature>(); var feature = context.Features.Get<IEndpointFeature>();
Assert.Equal(initialFeature, feature); Assert.Equal(initialFeature, feature);
Assert.Equal(endpoint, feature.Endpoint); Assert.Equal(endpoint, context.GetEndpoint());
} }
[Fact] [Fact]
@ -130,7 +130,7 @@ namespace Microsoft.AspNetCore.Http.Abstractions.Tests
// Assert // Assert
var feature = context.Features.Get<IEndpointFeature>(); var feature = context.Features.Get<IEndpointFeature>();
Assert.Equal(initialFeature, feature); Assert.Equal(initialFeature, feature);
Assert.Null(feature.Endpoint); Assert.Null(context.GetEndpoint());
} }
[Fact] [Fact]

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;

View File

@ -3,6 +3,7 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Http.Endpoints;
namespace Microsoft.AspNetCore.Routing.Matching namespace Microsoft.AspNetCore.Routing.Matching
{ {
@ -15,7 +16,6 @@ namespace Microsoft.AspNetCore.Routing.Matching
private Matcher _dfa; private Matcher _dfa;
private int[] _samples; private int[] _samples;
private EndpointSelectorContext _feature;
[GlobalSetup] [GlobalSetup]
public void Setup() public void Setup()
@ -30,34 +30,30 @@ namespace Microsoft.AspNetCore.Routing.Matching
_baseline = (BarebonesMatcher)SetupMatcher(new BarebonesMatcherBuilder()); _baseline = (BarebonesMatcher)SetupMatcher(new BarebonesMatcherBuilder());
_dfa = SetupMatcher(CreateDfaMatcherBuilder()); _dfa = SetupMatcher(CreateDfaMatcherBuilder());
_feature = new EndpointSelectorContext();
} }
[Benchmark(Baseline = true, OperationsPerInvoke = SampleCount)] [Benchmark(Baseline = true, OperationsPerInvoke = SampleCount)]
public async Task Baseline() public async Task Baseline()
{ {
var feature = _feature;
for (var i = 0; i < SampleCount; i++) for (var i = 0; i < SampleCount; i++)
{ {
var sample = _samples[i]; var sample = _samples[i];
var httpContext = Requests[sample]; var httpContext = Requests[sample];
await _baseline.Matchers[sample].MatchAsync(httpContext, feature); await _baseline.Matchers[sample].MatchAsync(httpContext);
Validate(httpContext, Endpoints[sample], feature.Endpoint); Validate(httpContext, Endpoints[sample], httpContext.GetEndpoint());
} }
} }
[Benchmark(OperationsPerInvoke = SampleCount)] [Benchmark(OperationsPerInvoke = SampleCount)]
public async Task Dfa() public async Task Dfa()
{ {
var feature = _feature;
for (var i = 0; i < SampleCount; i++) for (var i = 0; i < SampleCount; i++)
{ {
var sample = _samples[i]; var sample = _samples[i];
var httpContext = Requests[sample]; var httpContext = Requests[sample];
await _dfa.MatchAsync(httpContext, feature); await _dfa.MatchAsync(httpContext);
Validate(httpContext, Endpoints[sample], feature.Endpoint); Validate(httpContext, Endpoints[sample], httpContext.GetEndpoint());
} }
} }
} }
} }

View File

@ -162,7 +162,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
return false; return false;
} }
public Task ApplyAsync(HttpContext httpContext, EndpointSelectorContext context, CandidateSet candidates) public Task ApplyAsync(HttpContext httpContext, CandidateSet candidates)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
@ -179,7 +179,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
return false; return false;
} }
public Task ApplyAsync(HttpContext httpContext, EndpointSelectorContext context, CandidateSet candidates) public Task ApplyAsync(HttpContext httpContext, CandidateSet candidates)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }

View File

@ -3,6 +3,7 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Http.Endpoints;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
namespace Microsoft.AspNetCore.Routing.Matching namespace Microsoft.AspNetCore.Routing.Matching
@ -14,8 +15,6 @@ namespace Microsoft.AspNetCore.Routing.Matching
private BarebonesMatcher _baseline; private BarebonesMatcher _baseline;
private Matcher _dfa; private Matcher _dfa;
private EndpointSelectorContext _feature;
[GlobalSetup] [GlobalSetup]
public void Setup() public void Setup()
{ {
@ -25,32 +24,28 @@ namespace Microsoft.AspNetCore.Routing.Matching
_baseline = (BarebonesMatcher)SetupMatcher(new BarebonesMatcherBuilder()); _baseline = (BarebonesMatcher)SetupMatcher(new BarebonesMatcherBuilder());
_dfa = SetupMatcher(CreateDfaMatcherBuilder()); _dfa = SetupMatcher(CreateDfaMatcherBuilder());
_feature = new EndpointSelectorContext();
} }
[Benchmark(Baseline = true, OperationsPerInvoke = EndpointCount)] [Benchmark(Baseline = true, OperationsPerInvoke = EndpointCount)]
public async Task Baseline() public async Task Baseline()
{ {
var feature = _feature;
for (var i = 0; i < EndpointCount; i++) for (var i = 0; i < EndpointCount; i++)
{ {
var httpContext = Requests[i]; var httpContext = Requests[i];
await _baseline.Matchers[i].MatchAsync(httpContext, feature); await _baseline.Matchers[i].MatchAsync(httpContext);
Validate(httpContext, Endpoints[i], feature.Endpoint); Validate(httpContext, Endpoints[i], httpContext.GetEndpoint());
} }
} }
[Benchmark( OperationsPerInvoke = EndpointCount)] [Benchmark( OperationsPerInvoke = EndpointCount)]
public async Task Dfa() public async Task Dfa()
{ {
var feature = _feature;
for (var i = 0; i < EndpointCount; i++) for (var i = 0; i < EndpointCount; i++)
{ {
var httpContext = Requests[i]; var httpContext = Requests[i];
await _dfa.MatchAsync(httpContext, feature); await _dfa.MatchAsync(httpContext);
Validate(httpContext, Endpoints[i], feature.Endpoint); Validate(httpContext, Endpoints[i], httpContext.GetEndpoint());
} }
} }
} }
} }

View File

@ -4,6 +4,7 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Endpoints;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
namespace Microsoft.AspNetCore.Routing.Matching namespace Microsoft.AspNetCore.Routing.Matching
@ -43,40 +44,36 @@ namespace Microsoft.AspNetCore.Routing.Matching
public async Task Baseline() public async Task Baseline()
{ {
var httpContext = Requests[0]; var httpContext = Requests[0];
var feature = new EndpointSelectorContext(httpContext);
await _baseline.MatchAsync(httpContext, feature); await _baseline.MatchAsync(httpContext);
Validate(httpContext, Endpoints[0], feature.Endpoint); Validate(httpContext, Endpoints[0], httpContext.GetEndpoint());
} }
[Benchmark] [Benchmark]
public async Task Dfa() public async Task Dfa()
{ {
var httpContext = Requests[0]; var httpContext = Requests[0];
var feature = new EndpointSelectorContext(httpContext);
await _dfa.MatchAsync(httpContext, feature); await _dfa.MatchAsync(httpContext);
Validate(httpContext, Endpoints[0], feature.Endpoint); Validate(httpContext, Endpoints[0], httpContext.GetEndpoint());
} }
[Benchmark] [Benchmark]
public async Task LegacyTreeRouter() public async Task LegacyTreeRouter()
{ {
var httpContext = Requests[0]; var httpContext = Requests[0];
var feature = new EndpointSelectorContext(httpContext);
await _tree.MatchAsync(httpContext, feature); await _tree.MatchAsync(httpContext);
Validate(httpContext, Endpoints[0], feature.Endpoint); Validate(httpContext, Endpoints[0], httpContext.GetEndpoint());
} }
[Benchmark] [Benchmark]
public async Task LegacyRouter() public async Task LegacyRouter()
{ {
var httpContext = Requests[0]; var httpContext = Requests[0];
var feature = new EndpointSelectorContext(httpContext);
await _route.MatchAsync(httpContext, feature); await _route.MatchAsync(httpContext);
Validate(httpContext, Endpoints[0], feature.Endpoint); Validate(httpContext, Endpoints[0], httpContext.GetEndpoint());
} }
} }
} }

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Endpoints;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
namespace Microsoft.AspNetCore.Routing.Matching namespace Microsoft.AspNetCore.Routing.Matching
@ -23,7 +24,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
_candidates = new Candidate[] { new Candidate(endpoint), }; _candidates = new Candidate[] { new Candidate(endpoint), };
} }
public sealed override Task MatchAsync(HttpContext httpContext, EndpointSelectorContext context) public sealed override Task MatchAsync(HttpContext httpContext)
{ {
if (httpContext == null) if (httpContext == null)
{ {
@ -33,8 +34,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
var path = httpContext.Request.Path.Value; var path = httpContext.Request.Path.Value;
if (string.Equals(_endpoint.RoutePattern.RawText, path, StringComparison.OrdinalIgnoreCase)) if (string.Equals(_endpoint.RoutePattern.RawText, path, StringComparison.OrdinalIgnoreCase))
{ {
context.Endpoint = _endpoint; httpContext.SetEndpoint(_endpoint);
context.RouteValues = new RouteValueDictionary(); httpContext.Request.RouteValues = new RouteValueDictionary();
} }
return Task.CompletedTask; return Task.CompletedTask;

View File

@ -89,14 +89,6 @@ namespace Microsoft.AspNetCore.Routing
public EndpointNameMetadata(string endpointName) { } public EndpointNameMetadata(string endpointName) { }
public string EndpointName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } public string EndpointName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
} }
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public readonly partial struct EndpointSelectorContext
{
private readonly object _dummy;
public EndpointSelectorContext(Microsoft.AspNetCore.Http.HttpContext httpContext) { throw null; }
public Microsoft.AspNetCore.Http.Endpoint Endpoint { get { throw null; } set { } }
public Microsoft.AspNetCore.Routing.RouteValueDictionary RouteValues { get { throw null; } set { } }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=false, Inherited=false)] [System.AttributeUsageAttribute(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=false, Inherited=false)]
[System.Diagnostics.DebuggerDisplayAttribute("{DebuggerToString(),nq}")] [System.Diagnostics.DebuggerDisplayAttribute("{DebuggerToString(),nq}")]
public sealed partial class HostAttribute : System.Attribute, Microsoft.AspNetCore.Routing.IHostMetadata public sealed partial class HostAttribute : System.Attribute, Microsoft.AspNetCore.Routing.IHostMetadata
@ -572,14 +564,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
public abstract partial class EndpointSelector public abstract partial class EndpointSelector
{ {
protected EndpointSelector() { } protected EndpointSelector() { }
public abstract System.Threading.Tasks.Task SelectAsync(Microsoft.AspNetCore.Http.HttpContext httpContext, Microsoft.AspNetCore.Routing.EndpointSelectorContext context, Microsoft.AspNetCore.Routing.Matching.CandidateSet candidates); public abstract System.Threading.Tasks.Task SelectAsync(Microsoft.AspNetCore.Http.HttpContext httpContext, Microsoft.AspNetCore.Routing.Matching.CandidateSet candidates);
} }
public sealed partial class HostMatcherPolicy : Microsoft.AspNetCore.Routing.MatcherPolicy, Microsoft.AspNetCore.Routing.Matching.IEndpointComparerPolicy, Microsoft.AspNetCore.Routing.Matching.IEndpointSelectorPolicy, Microsoft.AspNetCore.Routing.Matching.INodeBuilderPolicy public sealed partial class HostMatcherPolicy : Microsoft.AspNetCore.Routing.MatcherPolicy, Microsoft.AspNetCore.Routing.Matching.IEndpointComparerPolicy, Microsoft.AspNetCore.Routing.Matching.IEndpointSelectorPolicy, Microsoft.AspNetCore.Routing.Matching.INodeBuilderPolicy
{ {
public HostMatcherPolicy() { } public HostMatcherPolicy() { }
public System.Collections.Generic.IComparer<Microsoft.AspNetCore.Http.Endpoint> Comparer { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } public System.Collections.Generic.IComparer<Microsoft.AspNetCore.Http.Endpoint> Comparer { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public override int Order { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } public override int Order { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public System.Threading.Tasks.Task ApplyAsync(Microsoft.AspNetCore.Http.HttpContext httpContext, Microsoft.AspNetCore.Routing.EndpointSelectorContext context, Microsoft.AspNetCore.Routing.Matching.CandidateSet candidates) { throw null; } public System.Threading.Tasks.Task ApplyAsync(Microsoft.AspNetCore.Http.HttpContext httpContext, Microsoft.AspNetCore.Routing.Matching.CandidateSet candidates) { throw null; }
public Microsoft.AspNetCore.Routing.Matching.PolicyJumpTable BuildJumpTable(int exitDestination, System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Routing.Matching.PolicyJumpTableEdge> edges) { throw null; } public Microsoft.AspNetCore.Routing.Matching.PolicyJumpTable BuildJumpTable(int exitDestination, System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Routing.Matching.PolicyJumpTableEdge> edges) { throw null; }
public System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Routing.Matching.PolicyNodeEdge> GetEdges(System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Http.Endpoint> endpoints) { throw null; } public System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Routing.Matching.PolicyNodeEdge> GetEdges(System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Http.Endpoint> endpoints) { throw null; }
bool Microsoft.AspNetCore.Routing.Matching.IEndpointSelectorPolicy.AppliesToEndpoints(System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Http.Endpoint> endpoints) { throw null; } bool Microsoft.AspNetCore.Routing.Matching.IEndpointSelectorPolicy.AppliesToEndpoints(System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Http.Endpoint> endpoints) { throw null; }
@ -590,7 +582,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
public HttpMethodMatcherPolicy() { } public HttpMethodMatcherPolicy() { }
public System.Collections.Generic.IComparer<Microsoft.AspNetCore.Http.Endpoint> Comparer { get { throw null; } } public System.Collections.Generic.IComparer<Microsoft.AspNetCore.Http.Endpoint> Comparer { get { throw null; } }
public override int Order { get { throw null; } } public override int Order { get { throw null; } }
public System.Threading.Tasks.Task ApplyAsync(Microsoft.AspNetCore.Http.HttpContext httpContext, Microsoft.AspNetCore.Routing.EndpointSelectorContext context, Microsoft.AspNetCore.Routing.Matching.CandidateSet candidates) { throw null; } public System.Threading.Tasks.Task ApplyAsync(Microsoft.AspNetCore.Http.HttpContext httpContext, Microsoft.AspNetCore.Routing.Matching.CandidateSet candidates) { throw null; }
public Microsoft.AspNetCore.Routing.Matching.PolicyJumpTable BuildJumpTable(int exitDestination, System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Routing.Matching.PolicyJumpTableEdge> edges) { throw null; } public Microsoft.AspNetCore.Routing.Matching.PolicyJumpTable BuildJumpTable(int exitDestination, System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Routing.Matching.PolicyJumpTableEdge> edges) { throw null; }
public System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Routing.Matching.PolicyNodeEdge> GetEdges(System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Http.Endpoint> endpoints) { throw null; } public System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Routing.Matching.PolicyNodeEdge> GetEdges(System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Http.Endpoint> endpoints) { throw null; }
bool Microsoft.AspNetCore.Routing.Matching.IEndpointSelectorPolicy.AppliesToEndpoints(System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Http.Endpoint> endpoints) { throw null; } bool Microsoft.AspNetCore.Routing.Matching.IEndpointSelectorPolicy.AppliesToEndpoints(System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Http.Endpoint> endpoints) { throw null; }
@ -603,7 +595,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
public partial interface IEndpointSelectorPolicy public partial interface IEndpointSelectorPolicy
{ {
bool AppliesToEndpoints(System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Http.Endpoint> endpoints); bool AppliesToEndpoints(System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Http.Endpoint> endpoints);
System.Threading.Tasks.Task ApplyAsync(Microsoft.AspNetCore.Http.HttpContext httpContext, Microsoft.AspNetCore.Routing.EndpointSelectorContext context, Microsoft.AspNetCore.Routing.Matching.CandidateSet candidates); System.Threading.Tasks.Task ApplyAsync(Microsoft.AspNetCore.Http.HttpContext httpContext, Microsoft.AspNetCore.Routing.Matching.CandidateSet candidates);
} }
public partial interface INodeBuilderPolicy public partial interface INodeBuilderPolicy
{ {

View File

@ -6,6 +6,7 @@ using System.Runtime.CompilerServices;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Endpoints;
using Microsoft.AspNetCore.Routing.Matching; using Microsoft.AspNetCore.Routing.Matching;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -55,12 +56,11 @@ namespace Microsoft.AspNetCore.Routing
public Task Invoke(HttpContext httpContext) public Task Invoke(HttpContext httpContext)
{ {
var feature = new EndpointSelectorContext(httpContext);
// There's already an endpoint, skip maching completely // There's already an endpoint, skip maching completely
if (feature.Endpoint != null) var endpoint = httpContext.GetEndpoint();
if (endpoint != null)
{ {
Log.MatchSkipped(_logger, feature.Endpoint); Log.MatchSkipped(_logger, endpoint);
return _next(httpContext); return _next(httpContext);
} }
@ -69,44 +69,45 @@ namespace Microsoft.AspNetCore.Routing
var matcherTask = InitializeAsync(); var matcherTask = InitializeAsync();
if (!matcherTask.IsCompletedSuccessfully) if (!matcherTask.IsCompletedSuccessfully)
{ {
return AwaitMatcher(this, httpContext, feature, matcherTask); return AwaitMatcher(this, httpContext, matcherTask);
} }
var matchTask = matcherTask.Result.MatchAsync(httpContext, feature); var matchTask = matcherTask.Result.MatchAsync(httpContext);
if (!matchTask.IsCompletedSuccessfully) if (!matchTask.IsCompletedSuccessfully)
{ {
return AwaitMatch(this, httpContext, feature, matchTask); return AwaitMatch(this, httpContext, matchTask);
} }
return SetRoutingAndContinue(httpContext, feature); return SetRoutingAndContinue(httpContext);
// Awaited fallbacks for when the Tasks do not synchronously complete // Awaited fallbacks for when the Tasks do not synchronously complete
static async Task AwaitMatcher(EndpointRoutingMiddleware middleware, HttpContext httpContext, EndpointSelectorContext feature, Task<Matcher> matcherTask) static async Task AwaitMatcher(EndpointRoutingMiddleware middleware, HttpContext httpContext, Task<Matcher> matcherTask)
{ {
var matcher = await matcherTask; var matcher = await matcherTask;
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext);
await middleware.SetRoutingAndContinue(httpContext, feature); await middleware.SetRoutingAndContinue(httpContext);
} }
static async Task AwaitMatch(EndpointRoutingMiddleware middleware, HttpContext httpContext, EndpointSelectorContext feature, Task matchTask) static async Task AwaitMatch(EndpointRoutingMiddleware middleware, HttpContext httpContext, Task matchTask)
{ {
await matchTask; await matchTask;
await middleware.SetRoutingAndContinue(httpContext, feature); await middleware.SetRoutingAndContinue(httpContext);
} }
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private Task SetRoutingAndContinue(HttpContext httpContext, EndpointSelectorContext feature) private Task SetRoutingAndContinue(HttpContext httpContext)
{ {
// If there was no mutation of the endpoint then log failure // If there was no mutation of the endpoint then log failure
if (feature.Endpoint is null) var endpoint = httpContext.GetEndpoint();
if (endpoint == null)
{ {
Log.MatchFailure(_logger); Log.MatchFailure(_logger);
} }
else else
{ {
Log.MatchSuccess(_logger, feature); Log.MatchSuccess(_logger, endpoint);
} }
return _next(httpContext); return _next(httpContext);
@ -115,8 +116,8 @@ namespace Microsoft.AspNetCore.Routing
// Initialization is async to avoid blocking threads while reflection and things // Initialization is async to avoid blocking threads while reflection and things
// of that nature take place. // of that nature take place.
// //
// We've seen cases where startup is very slow if we allow multiple threads to race // We've seen cases where startup is very slow if we allow multiple threads to race
// while initializing the set of endpoints/routes. Doing CPU intensive work is a // while initializing the set of endpoints/routes. Doing CPU intensive work is a
// blocking operation if you have a low core count and enough work to do. // blocking operation if you have a low core count and enough work to do.
private Task<Matcher> InitializeAsync() private Task<Matcher> InitializeAsync()
{ {
@ -184,9 +185,9 @@ namespace Microsoft.AspNetCore.Routing
new EventId(3, "MatchingSkipped"), new EventId(3, "MatchingSkipped"),
"Endpoint '{EndpointName}' already set, skipping route matching."); "Endpoint '{EndpointName}' already set, skipping route matching.");
public static void MatchSuccess(ILogger logger, EndpointSelectorContext context) public static void MatchSuccess(ILogger logger, Endpoint endpoint)
{ {
_matchSuccess(logger, context.Endpoint.DisplayName, null); _matchSuccess(logger, endpoint.DisplayName, null);
} }
public static void MatchFailure(ILogger logger) public static void MatchFailure(ILogger logger)

View File

@ -1,51 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Endpoints;
namespace Microsoft.AspNetCore.Routing
{
public readonly struct EndpointSelectorContext
{
private readonly HttpContext _httpContext;
public EndpointSelectorContext(HttpContext httpContext)
{
_httpContext = httpContext ?? throw new ArgumentNullException(nameof(httpContext));
}
/// <summary>
/// Gets or sets the selected <see cref="Http.Endpoint"/> for the current
/// request.
/// </summary>
public Endpoint Endpoint
{
get
{
return _httpContext.GetEndpoint();
}
set
{
_httpContext.SetEndpoint(value);
}
}
/// <summary>
/// Gets or sets the <see cref="RouteValueDictionary"/> associated with the currrent
/// request.
/// </summary>
public RouteValueDictionary RouteValues
{
get
{
return _httpContext.Request.RouteValues;
}
set
{
_httpContext.Request.RouteValues = value;
}
}
}
}

View File

@ -31,9 +31,9 @@ namespace Microsoft.AspNetCore.Routing.Matching
// Used in tests // Used in tests
internal Matcher CurrentMatcher => _cache.Value; internal Matcher CurrentMatcher => _cache.Value;
public override Task MatchAsync(HttpContext httpContext, EndpointSelectorContext context) public override Task MatchAsync(HttpContext httpContext)
{ {
return CurrentMatcher.MatchAsync(httpContext, context); return CurrentMatcher.MatchAsync(httpContext);
} }
private Matcher CreateMatcher(IReadOnlyList<Endpoint> endpoints) private Matcher CreateMatcher(IReadOnlyList<Endpoint> endpoints)

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Endpoints;
namespace Microsoft.AspNetCore.Routing.Matching namespace Microsoft.AspNetCore.Routing.Matching
{ {
@ -13,7 +14,6 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
public override Task SelectAsync( public override Task SelectAsync(
HttpContext httpContext, HttpContext httpContext,
EndpointSelectorContext context,
CandidateSet candidateSet) CandidateSet candidateSet)
{ {
if (httpContext == null) if (httpContext == null)
@ -26,14 +26,11 @@ namespace Microsoft.AspNetCore.Routing.Matching
throw new ArgumentNullException(nameof(candidateSet)); throw new ArgumentNullException(nameof(candidateSet));
} }
Select(httpContext, context, candidateSet.Candidates); Select(httpContext, candidateSet.Candidates);
return Task.CompletedTask; return Task.CompletedTask;
} }
internal static void Select( internal static void Select(HttpContext httpContext, CandidateState[] candidateState)
HttpContext httpContext,
EndpointSelectorContext context,
CandidateState[] candidateState)
{ {
// Fast path: We can specialize for trivial numbers of candidates since there can // Fast path: We can specialize for trivial numbers of candidates since there can
// be no ambiguities // be no ambiguities
@ -50,8 +47,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
ref var state = ref candidateState[0]; ref var state = ref candidateState[0];
if (CandidateSet.IsValidCandidate(ref state)) if (CandidateSet.IsValidCandidate(ref state))
{ {
context.Endpoint = state.Endpoint; httpContext.SetEndpoint(state.Endpoint);
context.RouteValues = state.Values; httpContext.Request.RouteValues = state.Values;
} }
break; break;
@ -61,7 +58,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Slow path: There's more than one candidate (to say nothing of validity) so we // Slow path: There's more than one candidate (to say nothing of validity) so we
// have to process for ambiguities. // have to process for ambiguities.
ProcessFinalCandidates(httpContext, context, candidateState); ProcessFinalCandidates(httpContext, candidateState);
break; break;
} }
} }
@ -69,7 +66,6 @@ namespace Microsoft.AspNetCore.Routing.Matching
private static void ProcessFinalCandidates( private static void ProcessFinalCandidates(
HttpContext httpContext, HttpContext httpContext,
EndpointSelectorContext context,
CandidateState[] candidateState) CandidateState[] candidateState)
{ {
Endpoint endpoint = null; Endpoint endpoint = null;
@ -100,7 +96,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
} }
else if (foundScore == state.Score) else if (foundScore == state.Score)
{ {
// This is the second match we've found of the same score, so there // This is the second match we've found of the same score, so there
// must be an ambiguity. // must be an ambiguity.
// //
// Don't worry about the 'null == state.Score' case, it returns false. // Don't worry about the 'null == state.Score' case, it returns false.
@ -114,8 +110,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
if (endpoint != null) if (endpoint != null)
{ {
context.Endpoint = endpoint; httpContext.SetEndpoint(endpoint);
context.RouteValues = values; httpContext.Request.RouteValues = values;
} }
} }

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Endpoints;
using Microsoft.AspNetCore.Routing.Patterns; using Microsoft.AspNetCore.Routing.Patterns;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -27,7 +28,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
_isDefaultEndpointSelector = selector is DefaultEndpointSelector; _isDefaultEndpointSelector = selector is DefaultEndpointSelector;
} }
public sealed override Task MatchAsync(HttpContext httpContext, EndpointSelectorContext context) public sealed override Task MatchAsync(HttpContext httpContext)
{ {
if (httpContext == null) if (httpContext == null)
{ {
@ -73,10 +74,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
ref readonly var candidate = ref candidates[0]; ref readonly var candidate = ref candidates[0];
// Just strict path matching // Just strict path matching (no route values)
if (candidate.Flags == Candidate.CandidateFlags.None) if (candidate.Flags == Candidate.CandidateFlags.None)
{ {
context.Endpoint = candidate.Endpoint; httpContext.SetEndpoint(candidate.Endpoint);
// We're done // We're done
return Task.CompletedTask; return Task.CompletedTask;
@ -181,7 +182,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
// Fast path that avoids allocating the candidate set. // Fast path that avoids allocating the candidate set.
// //
// We can use this when there are no policies and we're using the default selector. // We can use this when there are no policies and we're using the default selector.
DefaultEndpointSelector.Select(httpContext, context, candidateState); DefaultEndpointSelector.Select(httpContext, candidateState);
return Task.CompletedTask; return Task.CompletedTask;
} }
else if (policyCount == 0) else if (policyCount == 0)
@ -189,10 +190,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
// Fast path that avoids a state machine. // Fast path that avoids a state machine.
// //
// We can use this when there are no policies and a non-default selector. // We can use this when there are no policies and a non-default selector.
return _selector.SelectAsync(httpContext, context, new CandidateSet(candidateState)); return _selector.SelectAsync(httpContext, new CandidateSet(candidateState));
} }
return SelectEndpointWithPoliciesAsync(httpContext, context, policies, new CandidateSet(candidateState)); return SelectEndpointWithPoliciesAsync(httpContext, policies, new CandidateSet(candidateState));
} }
internal (Candidate[] candidates, IEndpointSelectorPolicy[] policies) FindCandidateSet( internal (Candidate[] candidates, IEndpointSelectorPolicy[] policies) FindCandidateSet(
@ -304,22 +305,21 @@ namespace Microsoft.AspNetCore.Routing.Matching
private async Task SelectEndpointWithPoliciesAsync( private async Task SelectEndpointWithPoliciesAsync(
HttpContext httpContext, HttpContext httpContext,
EndpointSelectorContext context,
IEndpointSelectorPolicy[] policies, IEndpointSelectorPolicy[] policies,
CandidateSet candidateSet) CandidateSet candidateSet)
{ {
for (var i = 0; i < policies.Length; i++) for (var i = 0; i < policies.Length; i++)
{ {
var policy = policies[i]; var policy = policies[i];
await policy.ApplyAsync(httpContext, context, candidateSet); await policy.ApplyAsync(httpContext, candidateSet);
if (context.Endpoint != null) if (httpContext.GetEndpoint() != null)
{ {
// This is a short circuit, the selector chose an endpoint. // This is a short circuit, the selector chose an endpoint.
return; return;
} }
} }
await _selector.SelectAsync(httpContext, context, candidateSet); await _selector.SelectAsync(httpContext, candidateSet);
} }
internal static class EventIds internal static class EventIds

View File

@ -1,9 +1,9 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Endpoints;
namespace Microsoft.AspNetCore.Routing.Matching namespace Microsoft.AspNetCore.Routing.Matching
{ {
@ -18,16 +18,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
/// Asynchronously selects an <see cref="Endpoint"/> from the <see cref="CandidateSet"/>. /// Asynchronously selects an <see cref="Endpoint"/> from the <see cref="CandidateSet"/>.
/// </summary> /// </summary>
/// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param> /// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
/// <param name="context">The <see cref="EndpointSelectorContext"/> associated with the current request.</param>
/// <param name="candidates">The <see cref="CandidateSet"/>.</param> /// <param name="candidates">The <see cref="CandidateSet"/>.</param>
/// <returns>A <see cref="Task"/> that completes asynchronously once endpoint selection is complete.</returns> /// <returns>A <see cref="Task"/> that completes asynchronously once endpoint selection is complete.</returns>
/// <remarks> /// <remarks>
/// An <see cref="EndpointSelector"/> should assign the <see cref="EndpointSelectorContext.Endpoint"/> /// An <see cref="EndpointSelector"/> should assign the endpoint by calling
/// and <see cref="EndpointSelectorContext.RouteValues"/> properties once an endpoint is selected. /// <see cref="EndpointHttpContextExtensions.SetEndpoint(HttpContext, Endpoint)"/>
/// and setting <see cref="HttpRequest.RouteValues"/> once an endpoint is selected.
/// </remarks> /// </remarks>
public abstract Task SelectAsync( public abstract Task SelectAsync(HttpContext httpContext, CandidateSet candidates);
HttpContext httpContext,
EndpointSelectorContext context,
CandidateSet candidates);
} }
} }

View File

@ -70,7 +70,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
}); });
} }
public Task ApplyAsync(HttpContext httpContext, EndpointSelectorContext context, CandidateSet candidates) public Task ApplyAsync(HttpContext httpContext, CandidateSet candidates)
{ {
if (httpContext == null) if (httpContext == null)
{ {

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Endpoints;
using Microsoft.Extensions.Internal; using Microsoft.Extensions.Internal;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Headers;
@ -84,10 +85,9 @@ namespace Microsoft.AspNetCore.Routing.Matching
/// For framework use only. /// For framework use only.
/// </summary> /// </summary>
/// <param name="httpContext"></param> /// <param name="httpContext"></param>
/// <param name="context"></param>
/// <param name="candidates"></param> /// <param name="candidates"></param>
/// <returns></returns> /// <returns></returns>
public Task ApplyAsync(HttpContext httpContext, EndpointSelectorContext context, CandidateSet candidates) public Task ApplyAsync(HttpContext httpContext, CandidateSet candidates)
{ {
if (httpContext == null) if (httpContext == null)
{ {
@ -168,7 +168,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
if (needs405Endpoint == true) if (needs405Endpoint == true)
{ {
// We saw some endpoints coming in, and we eliminated them all. // We saw some endpoints coming in, and we eliminated them all.
context.Endpoint = CreateRejectionEndpoint(methods.OrderBy(m => m, StringComparer.OrdinalIgnoreCase)); httpContext.SetEndpoint(CreateRejectionEndpoint(methods.OrderBy(m => m, StringComparer.OrdinalIgnoreCase)));
httpContext.Request.RouteValues = null;
} }
return Task.CompletedTask; return Task.CompletedTask;
@ -294,7 +295,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
// unlikely in a traditional MVC application. That's good. // unlikely in a traditional MVC application. That's good.
// //
// We don't bother returning a 405 when the CORS preflight method doesn't exist. // We don't bother returning a 405 when the CORS preflight method doesn't exist.
// The developer calling the API will see it as a CORS error, which is fine because // The developer calling the API will see it as a CORS error, which is fine because
// there isn't an endpoint to check for a CORS policy. // there isn't an endpoint to check for a CORS policy.
if (!edges.TryGetValue(new EdgeKey(AnyMethod, false), out var matches)) if (!edges.TryGetValue(new EdgeKey(AnyMethod, false), out var matches))
{ {

View File

@ -1,7 +1,8 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Endpoints;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -31,9 +32,6 @@ namespace Microsoft.AspNetCore.Routing.Matching
/// <param name="httpContext"> /// <param name="httpContext">
/// The <see cref="HttpContext"/> associated with the current request. /// The <see cref="HttpContext"/> associated with the current request.
/// </param> /// </param>
/// <param name="context">
/// The <see cref="EndpointSelectorContext"/> associated with the current request.
/// </param>
/// <param name="candidates">The <see cref="CandidateSet"/>.</param> /// <param name="candidates">The <see cref="CandidateSet"/>.</param>
/// <remarks> /// <remarks>
/// <para> /// <para>
@ -42,10 +40,12 @@ namespace Microsoft.AspNetCore.Routing.Matching
/// <see cref="CandidateSet.SetValidity(int, bool)"/> to <c>false</c> where desired. /// <see cref="CandidateSet.SetValidity(int, bool)"/> to <c>false</c> where desired.
/// </para> /// </para>
/// <para> /// <para>
/// To signal an error condition, set <see cref="EndpointSelectorContext.Endpoint"/> to an /// To signal an error condition, the <see cref="IEndpointSelectorPolicy"/> should assign the endpoint by
/// calling <see cref="EndpointHttpContextExtensions.SetEndpoint(HttpContext, Endpoint)"/>
/// and setting <see cref="HttpRequest.RouteValues"/> to an
/// <see cref="Endpoint"/> value that will produce the desired error when executed. /// <see cref="Endpoint"/> value that will produce the desired error when executed.
/// </para> /// </para>
/// </remarks> /// </remarks>
Task ApplyAsync(HttpContext httpContext, EndpointSelectorContext context, CandidateSet candidates); Task ApplyAsync(HttpContext httpContext, CandidateSet candidates);
} }
} }

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading.Tasks; using System.Threading.Tasks;
@ -17,10 +17,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
/// Attempts to asynchronously select an <see cref="Endpoint"/> for the current request. /// Attempts to asynchronously select an <see cref="Endpoint"/> for the current request.
/// </summary> /// </summary>
/// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param> /// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
/// <param name="context">
/// The <see cref="IEndpointFeature"/> associated with the current request. The
/// <see cref="EndpointSelectorContext"/> will be mutated to contain the result of the operation.</param>
/// <returns>A <see cref="Task"/> which represents the asynchronous completion of the operation.</returns> /// <returns>A <see cref="Task"/> which represents the asynchronous completion of the operation.</returns>
public abstract Task MatchAsync(HttpContext httpContext, EndpointSelectorContext context); public abstract Task MatchAsync(HttpContext httpContext);
} }
} }

View File

@ -105,7 +105,7 @@ namespace Microsoft.AspNetCore.Builder
// Assert // Assert
var feature = httpContext.Features.Get<IEndpointFeature>(); var feature = httpContext.Features.Get<IEndpointFeature>();
Assert.NotNull(feature); Assert.NotNull(feature);
Assert.Same(endpoint, feature.Endpoint); Assert.Same(endpoint, httpContext.GetEndpoint());
} }
[Fact] [Fact]

View File

@ -1,53 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Endpoints;
using Microsoft.AspNetCore.Routing.Patterns;
using Xunit;
namespace Microsoft.AspNetCore.Routing
{
public class EndpointSelectorContextTest
{
[Fact]
public void SettingEndpointSetsEndpointOnHttpContext()
{
var httpContext = new DefaultHttpContext();
var ep = new RouteEndpoint(
TestConstants.EmptyRequestDelegate,
RoutePatternFactory.Parse("/"),
0,
new EndpointMetadataCollection(),
"test");
new EndpointSelectorContext(httpContext)
{
Endpoint = ep,
};
// Assert
var endpoint = httpContext.GetEndpoint();
Assert.NotNull(endpoint);
Assert.Same(ep, endpoint);
}
[Fact]
public void SettingRouteValuesSetRouteValuesHttpContext()
{
var httpContext = new DefaultHttpContext();
var routeValues = new RouteValueDictionary(new { A = "1" });
new EndpointSelectorContext(httpContext)
{
RouteValues = routeValues
};
// Assert
Assert.NotNull(httpContext.Request.RouteValues);
Assert.Same(routeValues, httpContext.Request.RouteValues);
Assert.Single(httpContext.Request.RouteValues);
Assert.Equal("1", httpContext.Request.RouteValues["A"]);
}
}
}

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Endpoints;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
namespace Microsoft.AspNetCore.Routing.Matching namespace Microsoft.AspNetCore.Routing.Matching
@ -20,7 +21,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
Matchers = matchers; Matchers = matchers;
} }
public override Task MatchAsync(HttpContext httpContext, EndpointSelectorContext context) public override Task MatchAsync(HttpContext httpContext)
{ {
if (httpContext == null) if (httpContext == null)
{ {
@ -32,8 +33,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
if (Matchers[i].TryMatch(path)) if (Matchers[i].TryMatch(path))
{ {
context.Endpoint = Matchers[i].Endpoint; httpContext.SetEndpoint(Matchers[i].Endpoint);
context.RouteValues = new RouteValueDictionary(); httpContext.Request.RouteValues = new RouteValueDictionary();
} }
} }
@ -116,12 +117,12 @@ namespace Microsoft.AspNetCore.Routing.Matching
return Array.Empty<Candidate>(); return Array.Empty<Candidate>();
} }
public override Task MatchAsync(HttpContext httpContext, EndpointSelectorContext context) public override Task MatchAsync(HttpContext httpContext)
{ {
if (TryMatch(httpContext.Request.Path.Value)) if (TryMatch(httpContext.Request.Path.Value))
{ {
context.Endpoint = Endpoint; httpContext.SetEndpoint(Endpoint);
context.RouteValues = new RouteValueDictionary(); httpContext.Request.RouteValues = new RouteValueDictionary();
} }
return Task.CompletedTask; return Task.CompletedTask;

View File

@ -162,7 +162,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
public IReadOnlyList<RouteEndpoint> Endpoints { get; set; } public IReadOnlyList<RouteEndpoint> Endpoints { get; set; }
public override Task MatchAsync(HttpContext httpContext, EndpointSelectorContext context) public override Task MatchAsync(HttpContext httpContext)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Endpoints;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing.Patterns; using Microsoft.AspNetCore.Routing.Patterns;
using Moq; using Moq;
@ -21,14 +22,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
var scores = new int[] { }; var scores = new int[] { };
var candidateSet = CreateCandidateSet(endpoints, scores); var candidateSet = CreateCandidateSet(endpoints, scores);
var (httpContext, context) = CreateContext(); var httpContext = CreateContext();
var selector = CreateSelector(); var selector = CreateSelector();
// Act // Act
await selector.SelectAsync(httpContext, context, candidateSet); await selector.SelectAsync(httpContext, candidateSet);
// Assert // Assert
Assert.Null(context.Endpoint); Assert.Null(httpContext.GetEndpoint());
} }
[Fact] [Fact]
@ -42,14 +43,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
candidateSet[0].Values = new RouteValueDictionary(); candidateSet[0].Values = new RouteValueDictionary();
candidateSet.SetValidity(0, false); candidateSet.SetValidity(0, false);
var (httpContext, context) = CreateContext(); var httpContext = CreateContext();
var selector = CreateSelector(); var selector = CreateSelector();
// Act // Act
await selector.SelectAsync(httpContext, context, candidateSet); await selector.SelectAsync(httpContext, candidateSet);
// Assert // Assert
Assert.Null(context.Endpoint); Assert.Null(httpContext.GetEndpoint());
} }
[Fact] [Fact]
@ -63,14 +64,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
candidateSet[0].Values = new RouteValueDictionary(); candidateSet[0].Values = new RouteValueDictionary();
candidateSet.SetValidity(0, true); candidateSet.SetValidity(0, true);
var (httpContext, context) = CreateContext(); var httpContext = CreateContext();
var selector = CreateSelector(); var selector = CreateSelector();
// Act // Act
await selector.SelectAsync(httpContext, context, candidateSet); await selector.SelectAsync(httpContext, candidateSet);
// Assert // Assert
Assert.Same(endpoints[0], context.Endpoint); Assert.Same(endpoints[0], httpContext.GetEndpoint());
} }
[Fact] [Fact]
@ -84,14 +85,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
candidateSet.SetValidity(0, false); candidateSet.SetValidity(0, false);
candidateSet.SetValidity(1, true); candidateSet.SetValidity(1, true);
var (httpContext, context) = CreateContext(); var httpContext = CreateContext();
var selector = CreateSelector(); var selector = CreateSelector();
// Act // Act
await selector.SelectAsync(httpContext, context, candidateSet); await selector.SelectAsync(httpContext, candidateSet);
// Assert // Assert
Assert.Same(endpoints[1], context.Endpoint); Assert.Same(endpoints[1], httpContext.GetEndpoint());
} }
[Fact] [Fact]
@ -106,14 +107,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
candidateSet.SetValidity(1, true); candidateSet.SetValidity(1, true);
candidateSet.SetValidity(2, true); candidateSet.SetValidity(2, true);
var (httpContext, context) = CreateContext(); var httpContext = CreateContext();
var selector = CreateSelector(); var selector = CreateSelector();
// Act // Act
await selector.SelectAsync(httpContext, context, candidateSet); await selector.SelectAsync(httpContext, candidateSet);
// Assert // Assert
Assert.Same(endpoints[1], context.Endpoint); Assert.Same(endpoints[1], httpContext.GetEndpoint());
} }
[Fact] [Fact]
@ -137,14 +138,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
candidateSet.SetValidity(3, false); candidateSet.SetValidity(3, false);
candidateSet.SetValidity(4, true); candidateSet.SetValidity(4, true);
var (httpContext, context) = CreateContext(); var httpContext = CreateContext();
var selector = CreateSelector(); var selector = CreateSelector();
// Act // Act
await selector.SelectAsync(httpContext, context, candidateSet); await selector.SelectAsync(httpContext, candidateSet);
// Assert // Assert
Assert.Same(endpoints[4], context.Endpoint); Assert.Same(endpoints[4], httpContext.GetEndpoint());
} }
[Fact] [Fact]
@ -159,23 +160,22 @@ namespace Microsoft.AspNetCore.Routing.Matching
candidateSet.SetValidity(1, true); candidateSet.SetValidity(1, true);
candidateSet.SetValidity(2, true); candidateSet.SetValidity(2, true);
var (httpContext, context) = CreateContext(); var httpContext = CreateContext();
var selector = CreateSelector(); var selector = CreateSelector();
// Act // Act
var ex = await Assert.ThrowsAsync<AmbiguousMatchException>(() => selector.SelectAsync(httpContext, context, candidateSet)); var ex = await Assert.ThrowsAsync<AmbiguousMatchException>(() => selector.SelectAsync(httpContext, candidateSet));
// Assert // Assert
Assert.Equal( Assert.Equal(
@"The request matched multiple endpoints. Matches: " + Environment.NewLine + Environment.NewLine + @"The request matched multiple endpoints. Matches: " + Environment.NewLine + Environment.NewLine +
"test: /test2" + Environment.NewLine + "test: /test3", ex.Message); "test: /test2" + Environment.NewLine + "test: /test3", ex.Message);
Assert.Null(context.Endpoint); Assert.Null(httpContext.GetEndpoint());
} }
private static (HttpContext httpContext, EndpointSelectorContext context) CreateContext() private static HttpContext CreateContext()
{ {
var httpContext = new DefaultHttpContext(); return new DefaultHttpContext();
return (httpContext, new EndpointSelectorContext(httpContext));
} }
private static RouteEndpoint CreateEndpoint(string template) private static RouteEndpoint CreateEndpoint(string template)

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading.Tasks; using System.Threading.Tasks;
@ -14,13 +14,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher(template); var (matcher, endpoint) = CreateMatcher(template);
var (httpContext, context) = CreateContext(path); var httpContext = CreateContext(path);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint, keys, values); MatcherAssert.AssertMatch(httpContext, endpoint, keys, values);
} }
internal override Matcher CreateMatcher(params RouteEndpoint[] endpoints) internal override Matcher CreateMatcher(params RouteEndpoint[] endpoints)

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Endpoints;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing.Constraints; using Microsoft.AspNetCore.Routing.Constraints;
using Microsoft.AspNetCore.Routing.Patterns; using Microsoft.AspNetCore.Routing.Patterns;
@ -76,14 +77,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
var matcher = CreateDfaMatcher(endpointDataSource); var matcher = CreateDfaMatcher(endpointDataSource);
var (httpContext, context) = CreateContext(); var httpContext = CreateContext();
httpContext.Request.Path = "/1"; httpContext.Request.Path = "/1";
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
Assert.NotNull(context.Endpoint); Assert.NotNull(httpContext.GetEndpoint());
} }
[Fact] [Fact]
@ -97,14 +98,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
var matcher = CreateDfaMatcher(endpointDataSource); var matcher = CreateDfaMatcher(endpointDataSource);
var (httpContext, context) = CreateContext(); var httpContext = CreateContext();
httpContext.Request.Path = "/One"; httpContext.Request.Path = "/One";
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
Assert.Null(context.Endpoint); Assert.Null(httpContext.GetEndpoint());
} }
[Fact] [Fact]
@ -123,17 +124,17 @@ namespace Microsoft.AspNetCore.Routing.Matching
var matcher = CreateDfaMatcher(dataSource); var matcher = CreateDfaMatcher(dataSource);
var (httpContext, context) = CreateContext(); var httpContext = CreateContext();
httpContext.Request.Path = "/"; httpContext.Request.Path = "/";
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
Assert.Same(endpoint, context.Endpoint); Assert.Same(endpoint, httpContext.GetEndpoint());
Assert.Collection( Assert.Collection(
context.RouteValues.OrderBy(kvp => kvp.Key), httpContext.Request.RouteValues.OrderBy(kvp => kvp.Key),
(kvp) => (kvp) =>
{ {
Assert.Equal("action", kvp.Key); Assert.Equal("action", kvp.Key);
@ -162,14 +163,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
var matcher = CreateDfaMatcher(dataSource); var matcher = CreateDfaMatcher(dataSource);
var (httpContext, context) = CreateContext(); var httpContext = CreateContext();
httpContext.Request.Path = "/Login/Index"; httpContext.Request.Path = "/Login/Index";
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
Assert.Null(context.Endpoint); Assert.Null(httpContext.GetEndpoint());
} }
[Fact] [Fact]
@ -188,17 +189,17 @@ namespace Microsoft.AspNetCore.Routing.Matching
var matcher = CreateDfaMatcher(dataSource); var matcher = CreateDfaMatcher(dataSource);
var (httpContext, context) = CreateContext(); var httpContext = CreateContext();
httpContext.Request.Path = "/Home/Index/123"; httpContext.Request.Path = "/Home/Index/123";
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
Assert.Same(endpoint, context.Endpoint); Assert.Same(endpoint, httpContext.GetEndpoint());
Assert.Collection( Assert.Collection(
context.RouteValues.OrderBy(kvp => kvp.Key), httpContext.Request.RouteValues.OrderBy(kvp => kvp.Key),
(kvp) => (kvp) =>
{ {
Assert.Equal("action", kvp.Key); Assert.Equal("action", kvp.Key);
@ -237,18 +238,18 @@ namespace Microsoft.AspNetCore.Routing.Matching
var matcher = CreateDfaMatcher(dataSource); var matcher = CreateDfaMatcher(dataSource);
var (httpContext, context) = CreateContext(); var httpContext = CreateContext();
httpContext.Request.Path = path; httpContext.Request.Path = path;
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
Assert.Same(endpoint, context.Endpoint); Assert.Same(endpoint, httpContext.GetEndpoint());
Assert.Equal("TestAction", context.RouteValues["action"]); Assert.Equal("TestAction", httpContext.Request.RouteValues["action"]);
Assert.Equal("TestController", context.RouteValues["controller"]); Assert.Equal("TestController", httpContext.Request.RouteValues["controller"]);
Assert.Equal("17", context.RouteValues["id"]); Assert.Equal("17", httpContext.Request.RouteValues["id"]);
} }
[Fact] [Fact]
@ -272,22 +273,22 @@ namespace Microsoft.AspNetCore.Routing.Matching
var matcher = CreateDfaMatcher(dataSource); var matcher = CreateDfaMatcher(dataSource);
var (httpContext, context) = CreateContext(); var httpContext = CreateContext();
httpContext.Request.Path = "/Home/Index/123"; httpContext.Request.Path = "/Home/Index/123";
// Act 1 // Act 1
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert 1 // Assert 1
Assert.Same(endpoint1, context.Endpoint); Assert.Same(endpoint1, httpContext.GetEndpoint());
httpContext.Request.Path = "/Login/Index/123"; httpContext.Request.Path = "/Login/Index/123";
// Act 2 // Act 2
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert 2 // Assert 2
Assert.Same(endpoint2, context.Endpoint); Assert.Same(endpoint2, httpContext.GetEndpoint());
} }
[Fact] [Fact]
@ -306,17 +307,17 @@ namespace Microsoft.AspNetCore.Routing.Matching
var matcher = CreateDfaMatcher(dataSource); var matcher = CreateDfaMatcher(dataSource);
var (httpContext, context) = CreateContext(); var httpContext = CreateContext();
httpContext.Request.Path = "/ConventionalTransformerRoute/conventional-transformer/Index"; httpContext.Request.Path = "/ConventionalTransformerRoute/conventional-transformer/Index";
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
Assert.Same(endpoint, context.Endpoint); Assert.Same(endpoint, httpContext.GetEndpoint());
Assert.Collection( Assert.Collection(
context.RouteValues.OrderBy(kvp => kvp.Key), httpContext.Request.RouteValues.OrderBy(kvp => kvp.Key),
(kvp) => (kvp) =>
{ {
Assert.Equal("action", kvp.Key); Assert.Equal("action", kvp.Key);
@ -345,17 +346,17 @@ namespace Microsoft.AspNetCore.Routing.Matching
var matcher = CreateDfaMatcher(dataSource); var matcher = CreateDfaMatcher(dataSource);
var (httpContext, context) = CreateContext(); var httpContext = CreateContext();
httpContext.Request.Path = "/TestController"; httpContext.Request.Path = "/TestController";
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
Assert.Same(endpoint, context.Endpoint); Assert.Same(endpoint, httpContext.GetEndpoint());
Assert.Collection( Assert.Collection(
context.RouteValues.OrderBy(kvp => kvp.Key), httpContext.Request.RouteValues.OrderBy(kvp => kvp.Key),
(kvp) => (kvp) =>
{ {
Assert.Equal("action", kvp.Key); Assert.Equal("action", kvp.Key);
@ -383,14 +384,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
var matcher = CreateDfaMatcher(endpointDataSource); var matcher = CreateDfaMatcher(endpointDataSource);
var (httpContext, context) = CreateContext(); var httpContext = CreateContext();
httpContext.Request.Path = "/Teams"; httpContext.Request.Path = "/Teams";
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
Assert.Equal(lowerOrderEndpoint, context.Endpoint); Assert.Equal(lowerOrderEndpoint, httpContext.GetEndpoint());
} }
[Fact] [Fact]
@ -402,8 +403,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpointSelector = new Mock<EndpointSelector>(); var endpointSelector = new Mock<EndpointSelector>();
endpointSelector endpointSelector
.Setup(s => s.SelectAsync(It.IsAny<HttpContext>(), It.IsAny<EndpointSelectorContext>(), It.IsAny<CandidateSet>())) .Setup(s => s.SelectAsync(It.IsAny<HttpContext>(), It.IsAny<CandidateSet>()))
.Callback<HttpContext, EndpointSelectorContext, CandidateSet>((c, f, cs) => .Callback<HttpContext, CandidateSet>((c, cs) =>
{ {
Assert.Equal(2, cs.Count); Assert.Equal(2, cs.Count);
@ -417,7 +418,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
Assert.Equal(1, cs[1].Score); Assert.Equal(1, cs[1].Score);
Assert.Null(cs[1].Values); Assert.Null(cs[1].Values);
f.Endpoint = endpoint2; c.SetEndpoint(endpoint2);
}) })
.Returns(Task.CompletedTask); .Returns(Task.CompletedTask);
@ -429,14 +430,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
var matcher = CreateDfaMatcher(endpointDataSource, endpointSelector: endpointSelector.Object); var matcher = CreateDfaMatcher(endpointDataSource, endpointSelector: endpointSelector.Object);
var (httpContext, context) = CreateContext(); var httpContext = CreateContext();
httpContext.Request.Path = "/Teams"; httpContext.Request.Path = "/Teams";
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
Assert.Equal(endpoint2, context.Endpoint); Assert.Equal(endpoint2, httpContext.GetEndpoint());
} }
[Fact] [Fact]
@ -448,8 +449,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpointSelector = new Mock<EndpointSelector>(); var endpointSelector = new Mock<EndpointSelector>();
endpointSelector endpointSelector
.Setup(s => s.SelectAsync(It.IsAny<HttpContext>(), It.IsAny<EndpointSelectorContext>(), It.IsAny<CandidateSet>())) .Setup(s => s.SelectAsync(It.IsAny<HttpContext>(), It.IsAny<CandidateSet>()))
.Callback<HttpContext, EndpointSelectorContext, CandidateSet>((c, f, cs) => .Callback<HttpContext, CandidateSet>((c, cs) =>
{ {
Assert.Equal(2, cs.Count); Assert.Equal(2, cs.Count);
@ -463,7 +464,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
Assert.Equal(1, cs[1].Score); Assert.Equal(1, cs[1].Score);
Assert.Empty(cs[1].Values); Assert.Empty(cs[1].Values);
f.Endpoint = endpoint2; c.SetEndpoint(endpoint2);
}) })
.Returns(Task.CompletedTask); .Returns(Task.CompletedTask);
@ -475,14 +476,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
var matcher = CreateDfaMatcher(endpointDataSource, endpointSelector: endpointSelector.Object); var matcher = CreateDfaMatcher(endpointDataSource, endpointSelector: endpointSelector.Object);
var (httpContext, context) = CreateContext(); var httpContext = CreateContext();
httpContext.Request.Path = "/Teams"; httpContext.Request.Path = "/Teams";
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
Assert.Equal(endpoint2, context.Endpoint); Assert.Equal(endpoint2, httpContext.GetEndpoint());
} }
[Fact] [Fact]
@ -495,8 +496,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpointSelector = new Mock<EndpointSelector>(); var endpointSelector = new Mock<EndpointSelector>();
endpointSelector endpointSelector
.Setup(s => s.SelectAsync(It.IsAny<HttpContext>(), It.IsAny<EndpointSelectorContext>(), It.IsAny<CandidateSet>())) .Setup(s => s.SelectAsync(It.IsAny<HttpContext>(), It.IsAny<CandidateSet>()))
.Callback<HttpContext, EndpointSelectorContext, CandidateSet>((c, f, cs) => .Callback<HttpContext, CandidateSet>((c, cs) =>
{ {
Assert.Equal(2, cs.Count); Assert.Equal(2, cs.Count);
@ -510,7 +511,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
Assert.Equal(1, cs[1].Score); Assert.Equal(1, cs[1].Score);
Assert.Empty(cs[1].Values); Assert.Empty(cs[1].Values);
f.Endpoint = endpoint2; c.SetEndpoint(endpoint2);
}) })
.Returns(Task.CompletedTask); .Returns(Task.CompletedTask);
@ -522,14 +523,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
var matcher = CreateDfaMatcher(endpointDataSource, endpointSelector: endpointSelector.Object); var matcher = CreateDfaMatcher(endpointDataSource, endpointSelector: endpointSelector.Object);
var (httpContext, context) = CreateContext(); var httpContext = CreateContext();
httpContext.Request.Path = "/Teams"; httpContext.Request.Path = "/Teams";
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
Assert.Equal(endpoint2, context.Endpoint); Assert.Equal(endpoint2, httpContext.GetEndpoint());
} }
[Fact] [Fact]
@ -544,14 +545,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
var sink = new TestSink(); var sink = new TestSink();
var matcher = CreateDfaMatcher(endpointDataSource, loggerFactory: new TestLoggerFactory(sink, enabled: true)); var matcher = CreateDfaMatcher(endpointDataSource, loggerFactory: new TestLoggerFactory(sink, enabled: true));
var (httpContext, context) = CreateContext(); var httpContext = CreateContext();
httpContext.Request.Path = "/"; httpContext.Request.Path = "/";
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
Assert.Null(context.Endpoint); Assert.Null(httpContext.GetEndpoint());
Assert.Collection( Assert.Collection(
sink.Writes, sink.Writes,
@ -574,14 +575,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
var sink = new TestSink(); var sink = new TestSink();
var matcher = CreateDfaMatcher(endpointDataSource, loggerFactory: new TestLoggerFactory(sink, enabled: true)); var matcher = CreateDfaMatcher(endpointDataSource, loggerFactory: new TestLoggerFactory(sink, enabled: true));
var (httpContext, context) = CreateContext(); var httpContext = CreateContext();
httpContext.Request.Path = "/One"; httpContext.Request.Path = "/One";
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
Assert.Null(context.Endpoint); Assert.Null(httpContext.GetEndpoint());
Assert.Collection( Assert.Collection(
sink.Writes, sink.Writes,
@ -614,14 +615,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
var sink = new TestSink(); var sink = new TestSink();
var matcher = CreateDfaMatcher(endpointDataSource, loggerFactory: new TestLoggerFactory(sink, enabled: true)); var matcher = CreateDfaMatcher(endpointDataSource, loggerFactory: new TestLoggerFactory(sink, enabled: true));
var (httpContext, context) = CreateContext(); var httpContext = CreateContext();
httpContext.Request.Path = "/One"; httpContext.Request.Path = "/One";
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
Assert.Null(context.Endpoint); Assert.Null(httpContext.GetEndpoint());
Assert.Collection( Assert.Collection(
sink.Writes, sink.Writes,
@ -656,14 +657,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
var sink = new TestSink(); var sink = new TestSink();
var matcher = CreateDfaMatcher(endpointDataSource, loggerFactory: new TestLoggerFactory(sink, enabled: true)); var matcher = CreateDfaMatcher(endpointDataSource, loggerFactory: new TestLoggerFactory(sink, enabled: true));
var (httpContext, context) = CreateContext(); var httpContext = CreateContext();
httpContext.Request.Path = "/One"; httpContext.Request.Path = "/One";
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
Assert.Same(endpointDataSource.Endpoints[0], context.Endpoint); Assert.Same(endpointDataSource.Endpoints[0], httpContext.GetEndpoint());
Assert.Collection( Assert.Collection(
sink.Writes, sink.Writes,
@ -716,8 +717,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
.Setup(p => p.AppliesToEndpoints(It.IsAny<IReadOnlyList<Endpoint>>())).Returns(true); .Setup(p => p.AppliesToEndpoints(It.IsAny<IReadOnlyList<Endpoint>>())).Returns(true);
policy policy
.As<IEndpointSelectorPolicy>() .As<IEndpointSelectorPolicy>()
.Setup(p => p.ApplyAsync(It.IsAny<HttpContext>(), It.IsAny<EndpointSelectorContext>(), It.IsAny<CandidateSet>())) .Setup(p => p.ApplyAsync(It.IsAny<HttpContext>(), It.IsAny<CandidateSet>()))
.Returns<HttpContext, EndpointSelectorContext, CandidateSet>((c, f, cs) => .Returns<HttpContext, CandidateSet>((c, cs) =>
{ {
cs.SetValidity(1, false); cs.SetValidity(1, false);
return Task.CompletedTask; return Task.CompletedTask;
@ -725,14 +726,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
var matcher = CreateDfaMatcher(dataSource, policies: new[] { policy.Object, }); var matcher = CreateDfaMatcher(dataSource, policies: new[] { policy.Object, });
var (httpContext, context) = CreateContext(); var httpContext = CreateContext();
httpContext.Request.Path = "/test/17"; httpContext.Request.Path = "/test/17";
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
Assert.Same(dataSource.Endpoints[2], context.Endpoint); Assert.Same(dataSource.Endpoints[2], httpContext.GetEndpoint());
} }
[Fact] [Fact]
@ -752,22 +753,22 @@ namespace Microsoft.AspNetCore.Routing.Matching
.Setup(p => p.AppliesToEndpoints(It.IsAny<IReadOnlyList<Endpoint>>())).Returns(false); .Setup(p => p.AppliesToEndpoints(It.IsAny<IReadOnlyList<Endpoint>>())).Returns(false);
policy policy
.As<IEndpointSelectorPolicy>() .As<IEndpointSelectorPolicy>()
.Setup(p => p.ApplyAsync(It.IsAny<HttpContext>(), It.IsAny<EndpointSelectorContext>(), It.IsAny<CandidateSet>())) .Setup(p => p.ApplyAsync(It.IsAny<HttpContext>(), It.IsAny<CandidateSet>()))
.Returns<HttpContext, EndpointSelectorContext, CandidateSet>((c, f, cs) => .Returns<HttpContext, CandidateSet>((c, cs) =>
{ {
throw null; // Won't be called. throw null; // Won't be called.
}); });
var matcher = CreateDfaMatcher(dataSource, policies: new[] { policy.Object, }); var matcher = CreateDfaMatcher(dataSource, policies: new[] { policy.Object, });
var (httpContext, context) = CreateContext(); var httpContext = CreateContext();
httpContext.Request.Path = "/test/17"; httpContext.Request.Path = "/test/17";
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
Assert.Same(dataSource.Endpoints[1], context.Endpoint); Assert.Same(dataSource.Endpoints[1], httpContext.GetEndpoint());
} }
[Fact] [Fact]
@ -787,10 +788,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
.Setup(p => p.AppliesToEndpoints(It.IsAny<IReadOnlyList<Endpoint>>())).Returns(true); .Setup(p => p.AppliesToEndpoints(It.IsAny<IReadOnlyList<Endpoint>>())).Returns(true);
policy1 policy1
.As<IEndpointSelectorPolicy>() .As<IEndpointSelectorPolicy>()
.Setup(p => p.ApplyAsync(It.IsAny<HttpContext>(), It.IsAny<EndpointSelectorContext>(), It.IsAny<CandidateSet>())) .Setup(p => p.ApplyAsync(It.IsAny<HttpContext>(), It.IsAny<CandidateSet>()))
.Returns<HttpContext, EndpointSelectorContext, CandidateSet>((c, f, cs) => .Returns<HttpContext, CandidateSet>((c, cs) =>
{ {
f.Endpoint = cs[0].Endpoint; c.SetEndpoint(cs[0].Endpoint);
return Task.CompletedTask; return Task.CompletedTask;
}); });
@ -804,26 +805,24 @@ namespace Microsoft.AspNetCore.Routing.Matching
.Setup(p => p.AppliesToEndpoints(It.IsAny<IReadOnlyList<Endpoint>>())).Returns(true); .Setup(p => p.AppliesToEndpoints(It.IsAny<IReadOnlyList<Endpoint>>())).Returns(true);
policy2 policy2
.As<IEndpointSelectorPolicy>() .As<IEndpointSelectorPolicy>()
.Setup(p => p.ApplyAsync(It.IsAny<HttpContext>(), It.IsAny<EndpointSelectorContext>(), It.IsAny<CandidateSet>())) .Setup(p => p.ApplyAsync(It.IsAny<HttpContext>(), It.IsAny<CandidateSet>()))
.Throws(new InvalidOperationException()); .Throws(new InvalidOperationException());
var matcher = CreateDfaMatcher(dataSource, policies: new[] { policy1.Object, policy2.Object, }); var matcher = CreateDfaMatcher(dataSource, policies: new[] { policy1.Object, policy2.Object, });
var (httpContext, context) = CreateContext(); var httpContext = CreateContext();
httpContext.Request.Path = "/test/17"; httpContext.Request.Path = "/test/17";
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
Assert.Same(dataSource.Endpoints[0], context.Endpoint); Assert.Same(dataSource.Endpoints[0], httpContext.GetEndpoint());
} }
private (HttpContext httpContext, EndpointSelectorContext context) CreateContext() private HttpContext CreateContext()
{ {
var httpContext = new DefaultHttpContext(); return new DefaultHttpContext();
return (httpContext, new EndpointSelectorContext(httpContext));
} }
} }
} }

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
@ -28,13 +28,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher(template); var (matcher, endpoint) = CreateMatcher(template);
var (httpContext, context) = CreateContext(path); var httpContext = CreateContext(path);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint, keys, values); MatcherAssert.AssertMatch(httpContext, endpoint, keys, values);
} }
[Fact] [Fact]
@ -43,13 +43,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
// Arrange // Arrange
var endpoint = CreateEndpoint("/a/{b}/{c}", new { b = "17", c = "18", }); var endpoint = CreateEndpoint("/a/{b}/{c}", new { b = "17", c = "18", });
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/a"); var httpContext = CreateContext("/a");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint, new { b = "17", c = "18", }); MatcherAssert.AssertMatch(httpContext, endpoint, new { b = "17", c = "18", });
} }
[Fact] [Fact]
@ -58,13 +58,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
// Arrange // Arrange
var endpoint = CreateEndpoint("/a/{b}/{c}", new { b = "17", c = "18", d = "19" }); var endpoint = CreateEndpoint("/a/{b}/{c}", new { b = "17", c = "18", d = "19" });
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/a"); var httpContext = CreateContext("/a");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint, new { b = "17", c = "18", d = "19" }); MatcherAssert.AssertMatch(httpContext, endpoint, new { b = "17", c = "18", d = "19" });
} }
[Theory] [Theory]
@ -83,13 +83,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher(template); var (matcher, endpoint) = CreateMatcher(template);
var (httpContext, context) = CreateContext(path); var httpContext = CreateContext(path);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertNotMatch(context, httpContext); MatcherAssert.AssertNotMatch(httpContext);
} }
[Theory] [Theory]
@ -115,13 +115,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher(template); var (matcher, endpoint) = CreateMatcher(template);
var (httpContext, context) = CreateContext(path); var httpContext = CreateContext(path);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint, keys, values); MatcherAssert.AssertMatch(httpContext, endpoint, keys, values);
} }
[Theory] [Theory]
@ -138,13 +138,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher(template); var (matcher, endpoint) = CreateMatcher(template);
var (httpContext, context) = CreateContext(path); var httpContext = CreateContext(path);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertNotMatch(context, httpContext); MatcherAssert.AssertNotMatch(httpContext);
} }
[Theory] [Theory]
@ -162,13 +162,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher(template); var (matcher, endpoint) = CreateMatcher(template);
var (httpContext, context) = CreateContext(path); var httpContext = CreateContext(path);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint, keys, values); MatcherAssert.AssertMatch(httpContext, endpoint, keys, values);
} }
// Historically catchall segments don't match an empty segment, but only if it's // Historically catchall segments don't match an empty segment, but only if it's
@ -182,13 +182,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher(template); var (matcher, endpoint) = CreateMatcher(template);
var (httpContext, context) = CreateContext(path); var httpContext = CreateContext(path);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertNotMatch(context, httpContext); MatcherAssert.AssertNotMatch(httpContext);
// Need to access these to prevent a warning from the xUnit analyzer. // Need to access these to prevent a warning from the xUnit analyzer.
// Some of these tests will match (and process the values) and some will not. // Some of these tests will match (and process the values) and some will not.
@ -217,13 +217,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher(template); var (matcher, endpoint) = CreateMatcher(template);
var (httpContext, context) = CreateContext(path); var httpContext = CreateContext(path);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint, keys, values); MatcherAssert.AssertMatch(httpContext, endpoint, keys, values);
} }
[Theory] [Theory]
@ -237,13 +237,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher(template); var (matcher, endpoint) = CreateMatcher(template);
var (httpContext, context) = CreateContext(path); var httpContext = CreateContext(path);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertNotMatch(context, httpContext); MatcherAssert.AssertNotMatch(httpContext);
} }
[Theory] [Theory]
@ -266,13 +266,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher(template); var (matcher, endpoint) = CreateMatcher(template);
var (httpContext, context) = CreateContext(path); var httpContext = CreateContext(path);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint, keys, values); MatcherAssert.AssertMatch(httpContext, endpoint, keys, values);
} }
[Theory] [Theory]
@ -292,13 +292,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher(template); var (matcher, endpoint) = CreateMatcher(template);
var (httpContext, context) = CreateContext(path); var httpContext = CreateContext(path);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertNotMatch(context, httpContext); MatcherAssert.AssertNotMatch(httpContext);
} }
// Most of are copied from old routing tests that date back to the VS 2010 era. Enjoy! // Most of are copied from old routing tests that date back to the VS 2010 era. Enjoy!
@ -317,13 +317,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher(template); var (matcher, endpoint) = CreateMatcher(template);
var (httpContext, context) = CreateContext(path); var httpContext = CreateContext(path);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint, keys, values); MatcherAssert.AssertMatch(httpContext, endpoint, keys, values);
} }
[Theory] [Theory]
@ -347,13 +347,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
// Arrange // Arrange
var matcher = CreateMatcher(other, expected); var matcher = CreateMatcher(other, expected);
var (httpContext, context) = CreateContext(path); var httpContext = CreateContext(path);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, expected, ignoreValues: true); MatcherAssert.AssertMatch(httpContext, expected, ignoreValues: true);
} }
[Theory] [Theory]
@ -381,13 +381,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
// Arrange // Arrange
var matcher = CreateMatcher(other, expected); var matcher = CreateMatcher(other, expected);
var (httpContext, context) = CreateContext(path); var httpContext = CreateContext(path);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, expected, ignoreValues: true); MatcherAssert.AssertMatch(httpContext, expected, ignoreValues: true);
} }
[Theory] [Theory]
@ -434,13 +434,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var expected = endpoints[Array.IndexOf(templates, expectedTemplate)]; var expected = endpoints[Array.IndexOf(templates, expectedTemplate)];
var matcher = CreateMatcher(endpoints); var matcher = CreateMatcher(endpoints);
var (httpContext, context) = CreateContext(path); var httpContext = CreateContext(path);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, expected, ignoreValues: true); MatcherAssert.AssertMatch(httpContext, expected, ignoreValues: true);
} }
} }
} }

View File

@ -24,13 +24,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint = CreateEndpoint("/hello", hosts: new string[] { "contoso.com", }); var endpoint = CreateEndpoint("/hello", hosts: new string[] { "contoso.com", });
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/hello", "contoso.com"); var httpContext = CreateContext("/hello", "contoso.com");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
[Fact] [Fact]
@ -40,13 +40,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint = CreateEndpoint("/hello", hosts: new string[] { "contoso.com:8080", }); var endpoint = CreateEndpoint("/hello", hosts: new string[] { "contoso.com:8080", });
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/hello", "contoso.com:8080"); var httpContext = CreateContext("/hello", "contoso.com:8080");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
[Fact] [Fact]
@ -56,13 +56,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint = CreateEndpoint("/hello", hosts: new string[] { "æon.contoso.com", }); var endpoint = CreateEndpoint("/hello", hosts: new string[] { "æon.contoso.com", });
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/hello", "æon.contoso.com"); var httpContext = CreateContext("/hello", "æon.contoso.com");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
[Fact] [Fact]
@ -72,13 +72,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint = CreateEndpoint("/hello", hosts: new string[] { "contoso.com:8080", }); var endpoint = CreateEndpoint("/hello", hosts: new string[] { "contoso.com:8080", });
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/hello", "contoso.com:1111"); var httpContext = CreateContext("/hello", "contoso.com:1111");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertNotMatch(context, httpContext); MatcherAssert.AssertNotMatch(httpContext);
} }
[Fact] [Fact]
@ -88,13 +88,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint = CreateEndpoint("/hello", hosts: new string[] { "contoso.com:8080", }); var endpoint = CreateEndpoint("/hello", hosts: new string[] { "contoso.com:8080", });
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/hello", "www.contoso.com:8080"); var httpContext = CreateContext("/hello", "www.contoso.com:8080");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertNotMatch(context, httpContext); MatcherAssert.AssertNotMatch(httpContext);
} }
[Fact] [Fact]
@ -104,13 +104,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint = CreateEndpoint("/hello", hosts: new string[] { "*.contoso.com:8080", }); var endpoint = CreateEndpoint("/hello", hosts: new string[] { "*.contoso.com:8080", });
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/hello", "æon.contoso.com:8080"); var httpContext = CreateContext("/hello", "æon.contoso.com:8080");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
[Fact] [Fact]
@ -120,13 +120,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint = CreateEndpoint("/hello", hosts: new string[] { "*.contoso.com:8080", }); var endpoint = CreateEndpoint("/hello", hosts: new string[] { "*.contoso.com:8080", });
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/hello", "www.contoso.com:8080"); var httpContext = CreateContext("/hello", "www.contoso.com:8080");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
[Fact] [Fact]
@ -136,13 +136,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint = CreateEndpoint("/hello", hosts: new string[] { "Contoso.COM", }); var endpoint = CreateEndpoint("/hello", hosts: new string[] { "Contoso.COM", });
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/hello", "contoso.com"); var httpContext = CreateContext("/hello", "contoso.com");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
[Fact] [Fact]
@ -152,13 +152,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint = CreateEndpoint("/hello", hosts: new string[] { "contoso.com:80", }); var endpoint = CreateEndpoint("/hello", hosts: new string[] { "contoso.com:80", });
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/hello", "contoso.com", "http"); var httpContext = CreateContext("/hello", "contoso.com", "http");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
[Fact] [Fact]
@ -168,13 +168,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint = CreateEndpoint("/hello", hosts: new string[] { "contoso.com:443", }); var endpoint = CreateEndpoint("/hello", hosts: new string[] { "contoso.com:443", });
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/hello", "contoso.com", "https"); var httpContext = CreateContext("/hello", "contoso.com", "https");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
[Fact] [Fact]
@ -184,13 +184,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint = CreateEndpoint("/hello", hosts: new string[] { "contoso.com:443", }); var endpoint = CreateEndpoint("/hello", hosts: new string[] { "contoso.com:443", });
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/hello", null, "https"); var httpContext = CreateContext("/hello", null, "https");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertNotMatch(context, httpContext); MatcherAssert.AssertNotMatch(httpContext);
} }
[Fact] [Fact]
@ -200,13 +200,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint = CreateEndpoint("/hello", hosts: new string[] { "*:443", }); var endpoint = CreateEndpoint("/hello", hosts: new string[] { "*:443", });
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/hello", null, "https"); var httpContext = CreateContext("/hello", null, "https");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
[Fact] [Fact]
@ -216,13 +216,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint = CreateEndpoint("/hello"); var endpoint = CreateEndpoint("/hello");
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/hello", "contoso.com"); var httpContext = CreateContext("/hello", "contoso.com");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
[Fact] [Fact]
@ -232,13 +232,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint = CreateEndpoint("/hello", hosts: new string[] { }); var endpoint = CreateEndpoint("/hello", hosts: new string[] { });
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/hello", "contoso.com"); var httpContext = CreateContext("/hello", "contoso.com");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
[Fact] [Fact]
@ -248,13 +248,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint = CreateEndpoint("/hello", hosts: new string[] { "*", }); var endpoint = CreateEndpoint("/hello", hosts: new string[] { "*", });
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/hello", "contoso.com"); var httpContext = CreateContext("/hello", "contoso.com");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
[Fact] [Fact]
@ -264,13 +264,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint = CreateEndpoint("/hello", hosts: new string[] { "*:*", }); var endpoint = CreateEndpoint("/hello", hosts: new string[] { "*:*", });
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/hello", "contoso.com"); var httpContext = CreateContext("/hello", "contoso.com");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
private static Matcher CreateMatcher(params RouteEndpoint[] endpoints) private static Matcher CreateMatcher(params RouteEndpoint[] endpoints)
@ -290,7 +290,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
return builder.Build(); return builder.Build();
} }
internal static (HttpContext httpContext, EndpointSelectorContext context) CreateContext( internal static HttpContext CreateContext(
string path, string path,
string host, string host,
string scheme = null) string scheme = null)
@ -303,7 +303,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
httpContext.Request.Path = path; httpContext.Request.Path = path;
httpContext.Request.Scheme = scheme; httpContext.Request.Scheme = scheme;
return (httpContext, new EndpointSelectorContext(httpContext)); return httpContext;
} }
internal RouteEndpoint CreateEndpoint( internal RouteEndpoint CreateEndpoint(

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Endpoints;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing.Patterns; using Microsoft.AspNetCore.Routing.Patterns;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -25,13 +26,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint = CreateEndpoint("/hello", httpMethods: new string[] { "GET", }); var endpoint = CreateEndpoint("/hello", httpMethods: new string[] { "GET", });
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/hello", "GET"); var httpContext = CreateContext("/hello", "GET");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
[Fact] [Fact]
@ -41,13 +42,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint = CreateEndpoint("/hello", httpMethods: new string[] { "GET", }, acceptCorsPreflight: true); var endpoint = CreateEndpoint("/hello", httpMethods: new string[] { "GET", }, acceptCorsPreflight: true);
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/hello", "GET"); var httpContext = CreateContext("/hello", "GET");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
[Fact] [Fact]
@ -57,13 +58,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint = CreateEndpoint("/hello", httpMethods: new string[] { "GET", }, acceptCorsPreflight: true); var endpoint = CreateEndpoint("/hello", httpMethods: new string[] { "GET", }, acceptCorsPreflight: true);
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/hello", "GET", corsPreflight: true); var httpContext = CreateContext("/hello", "GET", corsPreflight: true);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
@ -74,14 +75,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint = CreateEndpoint("/hello", httpMethods: new string[] { "GET", }, acceptCorsPreflight: false); var endpoint = CreateEndpoint("/hello", httpMethods: new string[] { "GET", }, acceptCorsPreflight: false);
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/hello", "GET", corsPreflight: true); var httpContext = CreateContext("/hello", "GET", corsPreflight: true);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
Assert.NotSame(endpoint, context.Endpoint); Assert.NotSame(endpoint, httpContext.GetEndpoint());
Assert.Same(HttpMethodMatcherPolicy.Http405EndpointDisplayName, context.Endpoint.DisplayName); Assert.Same(HttpMethodMatcherPolicy.Http405EndpointDisplayName, httpContext.GetEndpoint().DisplayName);
} }
[Fact] [Fact]
@ -91,13 +92,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint = CreateEndpoint("/hello", httpMethods: new string[] { "GeT", }); var endpoint = CreateEndpoint("/hello", httpMethods: new string[] { "GeT", });
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/hello", "GET"); var httpContext = CreateContext("/hello", "GET");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
[Fact] [Fact]
@ -107,13 +108,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint = CreateEndpoint("/hello", httpMethods: new string[] { "GeT", }, acceptCorsPreflight: true); var endpoint = CreateEndpoint("/hello", httpMethods: new string[] { "GeT", }, acceptCorsPreflight: true);
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/hello", "GET", corsPreflight: true); var httpContext = CreateContext("/hello", "GET", corsPreflight: true);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
[Fact] [Fact]
@ -123,13 +124,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint = CreateEndpoint("/hello"); var endpoint = CreateEndpoint("/hello");
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/hello", "GET"); var httpContext = CreateContext("/hello", "GET");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
[Fact] [Fact]
@ -139,13 +140,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint = CreateEndpoint("/hello", acceptCorsPreflight: true); var endpoint = CreateEndpoint("/hello", acceptCorsPreflight: true);
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/hello", "GET", corsPreflight: true); var httpContext = CreateContext("/hello", "GET", corsPreflight: true);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
[Fact] // This matches because the endpoint accepts OPTIONS [Fact] // This matches because the endpoint accepts OPTIONS
@ -155,13 +156,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint = CreateEndpoint("/hello", acceptCorsPreflight: false); var endpoint = CreateEndpoint("/hello", acceptCorsPreflight: false);
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/hello", "GET", corsPreflight: true); var httpContext = CreateContext("/hello", "GET", corsPreflight: true);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
[Fact] [Fact]
@ -171,13 +172,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint = CreateEndpoint("/hello", httpMethods: new string[] { }); var endpoint = CreateEndpoint("/hello", httpMethods: new string[] { });
var matcher = CreateMatcher(endpoint); var matcher = CreateMatcher(endpoint);
var (httpContext, context) = CreateContext("/hello", "GET"); var httpContext = CreateContext("/hello", "GET");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
[Fact] // When all of the candidates handles specific verbs, use a 405 endpoint [Fact] // When all of the candidates handles specific verbs, use a 405 endpoint
@ -188,19 +189,19 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint2 = CreateEndpoint("/hello", httpMethods: new string[] { "DELETE" }); var endpoint2 = CreateEndpoint("/hello", httpMethods: new string[] { "DELETE" });
var matcher = CreateMatcher(endpoint1, endpoint2); var matcher = CreateMatcher(endpoint1, endpoint2);
var (httpContext, context) = CreateContext("/hello", "POST"); var httpContext = CreateContext("/hello", "POST");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
Assert.NotSame(endpoint1, context.Endpoint); Assert.NotSame(endpoint1, httpContext.GetEndpoint());
Assert.NotSame(endpoint2, context.Endpoint); Assert.NotSame(endpoint2, httpContext.GetEndpoint());
Assert.Same(HttpMethodMatcherPolicy.Http405EndpointDisplayName, context.Endpoint.DisplayName); Assert.Same(HttpMethodMatcherPolicy.Http405EndpointDisplayName, httpContext.GetEndpoint().DisplayName);
// Invoke the endpoint // Invoke the endpoint
await context.Endpoint.RequestDelegate(httpContext); await httpContext.GetEndpoint().RequestDelegate(httpContext);
Assert.Equal(405, httpContext.Response.StatusCode); Assert.Equal(405, httpContext.Response.StatusCode);
Assert.Equal("DELETE, GET, PUT", httpContext.Response.Headers["Allow"]); Assert.Equal("DELETE, GET, PUT", httpContext.Response.Headers["Allow"]);
} }
@ -213,13 +214,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint2 = CreateEndpoint("/hello", httpMethods: new string[] { "DELETE" }); var endpoint2 = CreateEndpoint("/hello", httpMethods: new string[] { "DELETE" });
var matcher = CreateMatcher(endpoint1, endpoint2); var matcher = CreateMatcher(endpoint1, endpoint2);
var (httpContext, context) = CreateContext("/hello", "POST", corsPreflight: true); var httpContext = CreateContext("/hello", "POST", corsPreflight: true);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertNotMatch(context, httpContext); MatcherAssert.AssertNotMatch(httpContext);
} }
[Fact] // When one of the candidates handles all verbs, dont use a 405 endpoint [Fact] // When one of the candidates handles all verbs, dont use a 405 endpoint
@ -230,13 +231,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint2 = CreateEndpoint("/hello", httpMethods: new string[] { "DELETE" }); var endpoint2 = CreateEndpoint("/hello", httpMethods: new string[] { "DELETE" });
var matcher = CreateMatcher(endpoint1, endpoint2); var matcher = CreateMatcher(endpoint1, endpoint2);
var (httpContext, context) = CreateContext("/hello", "POST"); var httpContext = CreateContext("/hello", "POST");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertNotMatch(context, httpContext); MatcherAssert.AssertNotMatch(httpContext);
} }
[Fact] [Fact]
@ -247,13 +248,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint2 = CreateEndpoint("/bar"); var endpoint2 = CreateEndpoint("/bar");
var matcher = CreateMatcher(endpoint1, endpoint2); var matcher = CreateMatcher(endpoint1, endpoint2);
var (httpContext, context) = CreateContext("/hello", "GET"); var httpContext = CreateContext("/hello", "GET");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint1); MatcherAssert.AssertMatch(httpContext, endpoint1);
} }
[Fact] [Fact]
@ -264,13 +265,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint2 = CreateEndpoint("/bar", httpMethods: new string[] { }); var endpoint2 = CreateEndpoint("/bar", httpMethods: new string[] { });
var matcher = CreateMatcher(endpoint1, endpoint2); var matcher = CreateMatcher(endpoint1, endpoint2);
var (httpContext, context) = CreateContext("/hello", "GET"); var httpContext = CreateContext("/hello", "GET");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint1); MatcherAssert.AssertMatch(httpContext, endpoint1);
} }
[Fact] // The non-http-method-specific endpoint is part of the same candidate set [Fact] // The non-http-method-specific endpoint is part of the same candidate set
@ -281,13 +282,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint2 = CreateEndpoint("/{x}", httpMethods: new string[] { }); var endpoint2 = CreateEndpoint("/{x}", httpMethods: new string[] { });
var matcher = CreateMatcher(endpoint1, endpoint2); var matcher = CreateMatcher(endpoint1, endpoint2);
var (httpContext, context) = CreateContext("/hello", "POST"); var httpContext = CreateContext("/hello", "POST");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint2, ignoreValues: true); MatcherAssert.AssertMatch(httpContext, endpoint2, ignoreValues: true);
} }
[Fact] // See https://github.com/aspnet/AspNetCore/issues/6415 [Fact] // See https://github.com/aspnet/AspNetCore/issues/6415
@ -298,24 +299,24 @@ namespace Microsoft.AspNetCore.Routing.Matching
var endpoint2 = CreateEndpoint("/hello", httpMethods: new string[] { "DELETE" }); var endpoint2 = CreateEndpoint("/hello", httpMethods: new string[] { "DELETE" });
var matcher = CreateMatcher(endpoint1, endpoint2); var matcher = CreateMatcher(endpoint1, endpoint2);
var (httpContext, context) = CreateContext("/hello", "POST"); var httpContext = CreateContext("/hello", "POST");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
Assert.NotSame(endpoint1, context.Endpoint); Assert.NotSame(endpoint1, httpContext.GetEndpoint());
Assert.NotSame(endpoint2, context.Endpoint); Assert.NotSame(endpoint2, httpContext.GetEndpoint());
Assert.Same(HttpMethodMatcherPolicy.Http405EndpointDisplayName, context.Endpoint.DisplayName); Assert.Same(HttpMethodMatcherPolicy.Http405EndpointDisplayName, httpContext.GetEndpoint().DisplayName);
// Invoke the endpoint // Invoke the endpoint
await context.Endpoint.RequestDelegate(httpContext); await httpContext.GetEndpoint().RequestDelegate(httpContext);
Assert.Equal(405, httpContext.Response.StatusCode); Assert.Equal(405, httpContext.Response.StatusCode);
Assert.Equal("DELETE, GET, PUT", httpContext.Response.Headers["Allow"]); Assert.Equal("DELETE, GET, PUT", httpContext.Response.Headers["Allow"]);
// Invoke the endpoint again to verify headers not duplicated // Invoke the endpoint again to verify headers not duplicated
await context.Endpoint.RequestDelegate(httpContext); await httpContext.GetEndpoint().RequestDelegate(httpContext);
Assert.Equal(405, httpContext.Response.StatusCode); Assert.Equal(405, httpContext.Response.StatusCode);
Assert.Equal("DELETE, GET, PUT", httpContext.Response.Headers["Allow"]); Assert.Equal("DELETE, GET, PUT", httpContext.Response.Headers["Allow"]);
} }
@ -337,7 +338,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
return builder.Build(); return builder.Build();
} }
internal static (HttpContext httpContext, EndpointSelectorContext context) CreateContext( internal static HttpContext CreateContext(
string path, string path,
string httpMethod, string httpMethod,
bool corsPreflight = false) bool corsPreflight = false)
@ -352,7 +353,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
httpContext.Request.Headers[AccessControlRequestMethod] = httpMethod; httpContext.Request.Headers[AccessControlRequestMethod] = httpMethod;
} }
return (httpContext, new EndpointSelectorContext(httpContext)); return httpContext;
} }
internal RouteEndpoint CreateEndpoint( internal RouteEndpoint CreateEndpoint(

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Endpoints;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
using Xunit.Sdk; using Xunit.Sdk;
@ -27,22 +28,22 @@ namespace Microsoft.AspNetCore.Routing.Matching
} }
} }
public static void AssertMatch(EndpointSelectorContext context, HttpContext httpContext, Endpoint expected) public static void AssertMatch(HttpContext httpContext, Endpoint expected)
{ {
AssertMatch(context, httpContext, expected, new RouteValueDictionary()); AssertMatch(httpContext, expected, new RouteValueDictionary());
} }
public static void AssertMatch(EndpointSelectorContext context, HttpContext httpContext, Endpoint expected, bool ignoreValues) public static void AssertMatch(HttpContext httpContext, Endpoint expected, bool ignoreValues)
{ {
AssertMatch(context, httpContext, expected, new RouteValueDictionary(), ignoreValues); AssertMatch(httpContext, expected, new RouteValueDictionary(), ignoreValues);
} }
public static void AssertMatch(EndpointSelectorContext context, HttpContext httpContext, Endpoint expected, object values) public static void AssertMatch(HttpContext httpContext, Endpoint expected, object values)
{ {
AssertMatch(context, httpContext, expected, new RouteValueDictionary(values)); AssertMatch(httpContext, expected, new RouteValueDictionary(values));
} }
public static void AssertMatch(EndpointSelectorContext context, HttpContext httpContext, Endpoint expected, string[] keys, string[] values) public static void AssertMatch(HttpContext httpContext, Endpoint expected, string[] keys, string[] values)
{ {
keys = keys ?? Array.Empty<string>(); keys = keys ?? Array.Empty<string>();
values = values ?? Array.Empty<string>(); values = values ?? Array.Empty<string>();
@ -53,17 +54,16 @@ namespace Microsoft.AspNetCore.Routing.Matching
} }
var zipped = keys.Zip(values, (k, v) => new KeyValuePair<string, object>(k, v)); var zipped = keys.Zip(values, (k, v) => new KeyValuePair<string, object>(k, v));
AssertMatch(context, httpContext, expected, new RouteValueDictionary(zipped)); AssertMatch(httpContext, expected, new RouteValueDictionary(zipped));
} }
public static void AssertMatch( public static void AssertMatch(
EndpointSelectorContext context,
HttpContext httpContext, HttpContext httpContext,
Endpoint expected, Endpoint expected,
RouteValueDictionary values, RouteValueDictionary values,
bool ignoreValues = false) bool ignoreValues = false)
{ {
if (context.Endpoint == null) if (httpContext.GetEndpoint() == null)
{ {
throw new XunitException($"Was expected to match '{expected.DisplayName}' but did not match."); throw new XunitException($"Was expected to match '{expected.DisplayName}' but did not match.");
} }
@ -75,11 +75,11 @@ namespace Microsoft.AspNetCore.Routing.Matching
throw new XunitException("RouteValues is null."); throw new XunitException("RouteValues is null.");
} }
if (!object.ReferenceEquals(expected, context.Endpoint)) if (!object.ReferenceEquals(expected, httpContext.GetEndpoint()))
{ {
throw new XunitException( throw new XunitException(
$"Was expected to match '{expected.DisplayName}' but matched " + $"Was expected to match '{expected.DisplayName}' but matched " +
$"'{context.Endpoint.DisplayName}' with values: {FormatRouteValues(actualValues)}."); $"'{httpContext.GetEndpoint().DisplayName}' with values: {FormatRouteValues(actualValues)}.");
} }
if (!ignoreValues) if (!ignoreValues)
@ -96,13 +96,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
} }
} }
public static void AssertNotMatch(EndpointSelectorContext context, HttpContext httpContext) public static void AssertNotMatch(HttpContext httpContext)
{ {
if (context.Endpoint != null) if (httpContext.GetEndpoint() != null)
{ {
throw new XunitException( throw new XunitException(
$"Was expected not to match '{context.Endpoint.DisplayName}' " + $"Was expected not to match '{httpContext.GetEndpoint().DisplayName}' " +
$"but matched with values: {FormatRouteValues(httpContext.Features.Get<IRouteValuesFeature>().RouteValues)}."); $"but matched with values: {FormatRouteValues(httpContext.Request.RouteValues)}.");
} }
} }

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading.Tasks; using System.Threading.Tasks;
@ -13,13 +13,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher("/"); var (matcher, endpoint) = CreateMatcher("/");
var (httpContext, context) = CreateContext("/"); var httpContext = CreateContext("/");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
[Fact] [Fact]
@ -27,13 +27,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher("/simple"); var (matcher, endpoint) = CreateMatcher("/simple");
var (httpContext, context) = CreateContext("/simple"); var httpContext = CreateContext("/simple");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
[Fact] [Fact]
@ -41,13 +41,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher("/simple"); var (matcher, endpoint) = CreateMatcher("/simple");
var (httpContext, context) = CreateContext("/simple/"); var httpContext = CreateContext("/simple/");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
[Theory] [Theory]
@ -58,13 +58,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher("/Simple"); var (matcher, endpoint) = CreateMatcher("/Simple");
var (httpContext, context) = CreateContext(path); var httpContext = CreateContext(path);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
// Some matchers will optimize for the ASCII case // Some matchers will optimize for the ASCII case
@ -75,13 +75,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher(template); var (matcher, endpoint) = CreateMatcher(template);
var (httpContext, context) = CreateContext(path); var httpContext = CreateContext(path);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
// Matchers should operate on the decoded representation - a matcher that calls // Matchers should operate on the decoded representation - a matcher that calls
@ -93,13 +93,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher(template); var (matcher, endpoint) = CreateMatcher(template);
var (httpContext, context) = CreateContext(path); var httpContext = CreateContext(path);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
[Theory] [Theory]
@ -113,13 +113,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher("/simple"); var (matcher, endpoint) = CreateMatcher("/simple");
var (httpContext, context) = CreateContext(path); var httpContext = CreateContext(path);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertNotMatch(context, httpContext); MatcherAssert.AssertNotMatch(httpContext);
} }
[Theory] [Theory]
@ -130,13 +130,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher(template); var (matcher, endpoint) = CreateMatcher(template);
var (httpContext, context) = CreateContext("/simple"); var httpContext = CreateContext("/simple");
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
// Matchers do their own 'splitting' of the path into segments, so including // Matchers do their own 'splitting' of the path into segments, so including
@ -153,13 +153,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher(template); var (matcher, endpoint) = CreateMatcher(template);
var (httpContext, context) = CreateContext(path); var httpContext = CreateContext(path);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint); MatcherAssert.AssertMatch(httpContext, endpoint);
} }
// Matchers do their own 'splitting' of the path into segments, so including // Matchers do their own 'splitting' of the path into segments, so including
@ -184,13 +184,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher(template); var (matcher, endpoint) = CreateMatcher(template);
var (httpContext, context) = CreateContext(path); var httpContext = CreateContext(path);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertNotMatch(context, httpContext); MatcherAssert.AssertNotMatch(httpContext);
} }
[Fact] [Fact]
@ -198,14 +198,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher("/{p}"); var (matcher, endpoint) = CreateMatcher("/{p}");
var (httpContext, context) = CreateContext("/14"); var httpContext = CreateContext("/14");
var values = new RouteValueDictionary(new { p = "14", }); var values = new RouteValueDictionary(new { p = "14", });
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint, values); MatcherAssert.AssertMatch(httpContext, endpoint, values);
} }
[Fact] [Fact]
@ -213,14 +213,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher("/{p:int}"); var (matcher, endpoint) = CreateMatcher("/{p:int}");
var (httpContext, context) = CreateContext("/14"); var httpContext = CreateContext("/14");
var values = new RouteValueDictionary(new { p = "14", }); var values = new RouteValueDictionary(new { p = "14", });
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint, values); MatcherAssert.AssertMatch(httpContext, endpoint, values);
} }
[Fact] [Fact]
@ -228,14 +228,14 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher("/{p}"); var (matcher, endpoint) = CreateMatcher("/{p}");
var (httpContext, context) = CreateContext("/14/"); var httpContext = CreateContext("/14/");
var values = new RouteValueDictionary(new { p = "14", }); var values = new RouteValueDictionary(new { p = "14", });
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint, values); MatcherAssert.AssertMatch(httpContext, endpoint, values);
} }
[Fact] [Fact]
@ -243,7 +243,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher("/foo/{ }/{.!$%}/{dynamic.data}"); var (matcher, endpoint) = CreateMatcher("/foo/{ }/{.!$%}/{dynamic.data}");
var (httpContext, context) = CreateContext("/foo/space/weirdmatch/matcherid"); var httpContext = CreateContext("/foo/space/weirdmatch/matcherid");
var values = new RouteValueDictionary() var values = new RouteValueDictionary()
{ {
{ " ", "space" }, { " ", "space" },
@ -252,10 +252,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
}; };
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint, values); MatcherAssert.AssertMatch(httpContext, endpoint, values);
} }
[Theory] [Theory]
@ -267,13 +267,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher("/{p}"); var (matcher, endpoint) = CreateMatcher("/{p}");
var (httpContext, context) = CreateContext(path); var httpContext = CreateContext(path);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertNotMatch(context, httpContext); MatcherAssert.AssertNotMatch(httpContext);
} }
[Theory] [Theory]
@ -288,13 +288,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher(template); var (matcher, endpoint) = CreateMatcher(template);
var (httpContext, context) = CreateContext(path); var httpContext = CreateContext(path);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertMatch(context, httpContext, endpoint, keys, values); MatcherAssert.AssertMatch(httpContext, endpoint, keys, values);
} }
[Theory] [Theory]
@ -317,13 +317,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
// Arrange // Arrange
var (matcher, endpoint) = CreateMatcher(template); var (matcher, endpoint) = CreateMatcher(template);
var (httpContext, context) = CreateContext(path); var httpContext = CreateContext(path);
// Act // Act
await matcher.MatchAsync(httpContext, context); await matcher.MatchAsync(httpContext);
// Assert // Assert
MatcherAssert.AssertNotMatch(context, httpContext); MatcherAssert.AssertNotMatch(httpContext);
} }
} }
} }

View File

@ -14,13 +14,13 @@ namespace Microsoft.AspNetCore.Routing.Matching
{ {
internal abstract Matcher CreateMatcher(params RouteEndpoint[] endpoints); internal abstract Matcher CreateMatcher(params RouteEndpoint[] endpoints);
internal static (HttpContext httpContext, EndpointSelectorContext context) CreateContext(string path) internal static HttpContext CreateContext(string path)
{ {
var httpContext = new DefaultHttpContext(); var httpContext = new DefaultHttpContext();
httpContext.Request.Method = "TEST"; httpContext.Request.Method = "TEST";
httpContext.Request.Path = path; httpContext.Request.Path = path;
httpContext.RequestServices = CreateServices(); httpContext.RequestServices = CreateServices();
return (httpContext, new EndpointSelectorContext(httpContext)); return httpContext;
} }
// The older routing implementations retrieve services when they first execute. // The older routing implementations retrieve services when they first execute.

View File

@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
_inner = inner; _inner = inner;
} }
public async override Task MatchAsync(HttpContext httpContext, EndpointSelectorContext context) public async override Task MatchAsync(HttpContext httpContext)
{ {
if (httpContext == null) if (httpContext == null)
{ {
@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
if (routeContext.Handler != null) if (routeContext.Handler != null)
{ {
context.RouteValues = routeContext.RouteData.Values; httpContext.Request.RouteValues = routeContext.RouteData.Values;
await routeContext.Handler(httpContext); await routeContext.Handler(httpContext);
} }
} }

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Endpoints;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing.Patterns; using Microsoft.AspNetCore.Routing.Patterns;
using Microsoft.AspNetCore.Routing.TestObjects; using Microsoft.AspNetCore.Routing.TestObjects;
@ -96,13 +97,11 @@ namespace Microsoft.AspNetCore.Routing.Matching
public async Task RouteAsync(RouteContext routeContext) public async Task RouteAsync(RouteContext routeContext)
{ {
var context = new EndpointSelectorContext(routeContext.HttpContext);
// This is needed due to a quirk of our tests - they reuse the endpoint feature. // This is needed due to a quirk of our tests - they reuse the endpoint feature.
context.Endpoint = null; routeContext.HttpContext.SetEndpoint(null);
await _selector.SelectAsync(routeContext.HttpContext, context, new CandidateSet(_candidates, _values, _scores)); await _selector.SelectAsync(routeContext.HttpContext, new CandidateSet(_candidates, _values, _scores));
if (context.Endpoint != null) if (routeContext.HttpContext.GetEndpoint() != null)
{ {
routeContext.Handler = (_) => Task.CompletedTask; routeContext.Handler = (_) => Task.CompletedTask;
} }

View File

@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
_inner = inner; _inner = inner;
} }
public async override Task MatchAsync(HttpContext httpContext, EndpointSelectorContext context) public async override Task MatchAsync(HttpContext httpContext)
{ {
if (httpContext == null) if (httpContext == null)
{ {
@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
if (routeContext.Handler != null) if (routeContext.Handler != null)
{ {
context.RouteValues = routeContext.RouteData.Values; httpContext.Request.RouteValues = routeContext.RouteData.Values;
await routeContext.Handler(httpContext); await routeContext.Handler(httpContext);
} }
} }

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Endpoints;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing.Internal; using Microsoft.AspNetCore.Routing.Internal;
using Microsoft.AspNetCore.Routing.Template; using Microsoft.AspNetCore.Routing.Template;
@ -99,13 +100,11 @@ namespace Microsoft.AspNetCore.Routing.Matching
public async Task RouteAsync(RouteContext routeContext) public async Task RouteAsync(RouteContext routeContext)
{ {
var context = new EndpointSelectorContext(routeContext.HttpContext);
// This is needed due to a quirk of our tests - they reuse the endpoint feature. // This is needed due to a quirk of our tests - they reuse the endpoint feature.
context.Endpoint = null; routeContext.HttpContext.SetEndpoint(null);
await _selector.SelectAsync(routeContext.HttpContext, context, new CandidateSet(_candidates, _values, _scores)); await _selector.SelectAsync(routeContext.HttpContext, new CandidateSet(_candidates, _values, _scores));
if (context.Endpoint != null) if (routeContext.HttpContext.GetEndpoint() != null)
{ {
routeContext.Handler = (_) => Task.CompletedTask; routeContext.Handler = (_) => Task.CompletedTask;
} }

View File

@ -1,8 +1,9 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Endpoints;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing.Matching; using Microsoft.AspNetCore.Routing.Matching;
@ -17,12 +18,12 @@ namespace Microsoft.AspNetCore.Routing.TestObjects
_isHandled = isHandled; _isHandled = isHandled;
} }
public override Task MatchAsync(HttpContext httpContext, EndpointSelectorContext context) public override Task MatchAsync(HttpContext httpContext)
{ {
if (_isHandled) if (_isHandled)
{ {
context.RouteValues = new RouteValueDictionary(new { controller = "Home", action = "Index" }); httpContext.Request.RouteValues = new RouteValueDictionary(new { controller = "Home", action = "Index" });
context.Endpoint = new Endpoint(TestConstants.EmptyRequestDelegate, EndpointMetadataCollection.Empty, "Test endpoint"); httpContext.SetEndpoint(new Endpoint(TestConstants.EmptyRequestDelegate, EndpointMetadataCollection.Empty, "Test endpoint"));
} }
return Task.CompletedTask; return Task.CompletedTask;

View File

@ -50,7 +50,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
if (action?.ActionConstraints?.Count > 0 && HasSignificantActionConstraint(action)) if (action?.ActionConstraints?.Count > 0 && HasSignificantActionConstraint(action))
{ {
// We need to check for some specific action constraint implementations. // We need to check for some specific action constraint implementations.
// We've implemented consumes, and HTTP method support inside endpoint routing, so // We've implemented consumes, and HTTP method support inside endpoint routing, so
// we don't need to run an 'action constraint phase' if those are the only constraints. // we don't need to run an 'action constraint phase' if those are the only constraints.
return true; return true;
} }
@ -81,7 +81,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
} }
} }
public Task ApplyAsync(HttpContext httpContext, EndpointSelectorContext context, CandidateSet candidateSet) public Task ApplyAsync(HttpContext httpContext, CandidateSet candidateSet)
{ {
var finalMatches = EvaluateActionConstraints(httpContext, candidateSet); var finalMatches = EvaluateActionConstraints(httpContext, candidateSet);

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Endpoints;
using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Routing.Matching; using Microsoft.AspNetCore.Routing.Matching;
@ -53,7 +54,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
return endpoints.Any(e => e.Metadata.GetMetadata<IConsumesMetadata>()?.ContentTypes.Count > 0); return endpoints.Any(e => e.Metadata.GetMetadata<IConsumesMetadata>()?.ContentTypes.Count > 0);
} }
public Task ApplyAsync(HttpContext httpContext, EndpointSelectorContext context, CandidateSet candidates) public Task ApplyAsync(HttpContext httpContext, CandidateSet candidates)
{ {
if (httpContext == null) if (httpContext == null)
{ {
@ -106,7 +107,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
} }
var contentType = httpContext.Request.ContentType; var contentType = httpContext.Request.ContentType;
var mediaType = string.IsNullOrEmpty(contentType) ? (MediaType?)null : new MediaType(contentType); var mediaType = string.IsNullOrEmpty(contentType) ? (MediaType?)null : new MediaType(contentType);
var matched = false; var matched = false;
for (var j = 0; j < metadata.ContentTypes.Count; j++) for (var j = 0; j < metadata.ContentTypes.Count; j++)
@ -145,7 +146,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
if (needs415Endpoint == true) if (needs415Endpoint == true)
{ {
// We saw some endpoints coming in, and we eliminated them all. // We saw some endpoints coming in, and we eliminated them all.
context.Endpoint = CreateRejectionEndpoint(); httpContext.SetEndpoint(CreateRejectionEndpoint());
} }
return Task.CompletedTask; return Task.CompletedTask;
@ -220,7 +221,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
var mediaType = new MediaType(contentType); var mediaType = new MediaType(contentType);
// Example: 'application/json' is subset of 'application/*' // Example: 'application/json' is subset of 'application/*'
// //
// This means that when the request has content-type 'application/json' an endpoint // This means that when the request has content-type 'application/json' an endpoint
// what consumes 'application/*' should match. // what consumes 'application/*' should match.
if (edgeKey.IsSubsetOf(mediaType)) if (edgeKey.IsSubsetOf(mediaType))

View File

@ -60,13 +60,13 @@ namespace Microsoft.AspNetCore.Mvc.Routing
return false; return false;
} }
public Task ApplyAsync(HttpContext httpContext, EndpointSelectorContext context, CandidateSet candidates) public Task ApplyAsync(HttpContext httpContext, CandidateSet candidates)
{ {
if (httpContext == null) if (httpContext == null)
{ {
throw new ArgumentNullException(nameof(httpContext)); throw new ArgumentNullException(nameof(httpContext));
} }
if (candidates == null) if (candidates == null)
{ {
throw new ArgumentNullException(nameof(candidates)); throw new ArgumentNullException(nameof(candidates));
@ -97,7 +97,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
// If there's no match this is a configuration error. We can't really check // If there's no match this is a configuration error. We can't really check
// during startup that the action you configured exists. // during startup that the action you configured exists.
throw new InvalidOperationException( throw new InvalidOperationException(
"Cannot find the fallback endpoint specified by route values: " + "Cannot find the fallback endpoint specified by route values: " +
"{ " + string.Join(", ", metadata.Values.Select(kvp => $"{kvp.Key}: {kvp.Value}")) + " }."); "{ " + string.Join(", ", metadata.Values.Select(kvp => $"{kvp.Key}: {kvp.Value}")) + " }.");
} }

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Endpoints;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Routing.Matching; using Microsoft.AspNetCore.Routing.Matching;
using Microsoft.AspNetCore.Routing.Patterns; using Microsoft.AspNetCore.Routing.Patterns;
@ -326,13 +327,12 @@ namespace Microsoft.AspNetCore.Mvc.Routing
}; };
var candidates = CreateCandidateSet(endpoints); var candidates = CreateCandidateSet(endpoints);
var context = new EndpointSelectorContext();
var httpContext = new DefaultHttpContext(); var httpContext = new DefaultHttpContext();
var policy = CreatePolicy(); var policy = CreatePolicy();
// Act // Act
await policy.ApplyAsync(httpContext, context, candidates); await policy.ApplyAsync(httpContext, candidates);
// Assert // Assert
Assert.True(candidates.IsValidCandidate(0)); Assert.True(candidates.IsValidCandidate(0));
@ -348,13 +348,12 @@ namespace Microsoft.AspNetCore.Mvc.Routing
}; };
var candidates = CreateCandidateSet(endpoints); var candidates = CreateCandidateSet(endpoints);
var context = new EndpointSelectorContext();
var httpContext = new DefaultHttpContext(); var httpContext = new DefaultHttpContext();
var policy = CreatePolicy(); var policy = CreatePolicy();
// Act // Act
await policy.ApplyAsync(httpContext, context, candidates); await policy.ApplyAsync(httpContext, candidates);
// Assert // Assert
Assert.True(candidates.IsValidCandidate(0)); Assert.True(candidates.IsValidCandidate(0));
@ -370,13 +369,12 @@ namespace Microsoft.AspNetCore.Mvc.Routing
}; };
var candidates = CreateCandidateSet(endpoints); var candidates = CreateCandidateSet(endpoints);
var context = new EndpointSelectorContext();
var httpContext = new DefaultHttpContext(); var httpContext = new DefaultHttpContext();
var policy = CreatePolicy(); var policy = CreatePolicy();
// Act // Act
await policy.ApplyAsync(httpContext, context, candidates); await policy.ApplyAsync(httpContext, candidates);
// Assert // Assert
Assert.True(candidates.IsValidCandidate(0)); Assert.True(candidates.IsValidCandidate(0));
@ -392,7 +390,6 @@ namespace Microsoft.AspNetCore.Mvc.Routing
}; };
var candidates = CreateCandidateSet(endpoints); var candidates = CreateCandidateSet(endpoints);
var context = new EndpointSelectorContext();
var httpContext = new DefaultHttpContext() var httpContext = new DefaultHttpContext()
{ {
Request = Request =
@ -404,7 +401,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
var policy = CreatePolicy(); var policy = CreatePolicy();
// Act // Act
await policy.ApplyAsync(httpContext, context, candidates); await policy.ApplyAsync(httpContext, candidates);
// Assert // Assert
Assert.True(candidates.IsValidCandidate(0)); Assert.True(candidates.IsValidCandidate(0));
@ -420,7 +417,6 @@ namespace Microsoft.AspNetCore.Mvc.Routing
}; };
var candidates = CreateCandidateSet(endpoints); var candidates = CreateCandidateSet(endpoints);
var context = new EndpointSelectorContext();
var httpContext = new DefaultHttpContext() var httpContext = new DefaultHttpContext()
{ {
Request = Request =
@ -432,7 +428,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
var policy = CreatePolicy(); var policy = CreatePolicy();
// Act // Act
await policy.ApplyAsync(httpContext, context, candidates); await policy.ApplyAsync(httpContext, candidates);
// Assert // Assert
Assert.True(candidates.IsValidCandidate(0)); Assert.True(candidates.IsValidCandidate(0));
@ -448,7 +444,6 @@ namespace Microsoft.AspNetCore.Mvc.Routing
}; };
var candidates = CreateCandidateSet(endpoints); var candidates = CreateCandidateSet(endpoints);
var context = new EndpointSelectorContext();
var httpContext = new DefaultHttpContext() var httpContext = new DefaultHttpContext()
{ {
Request = Request =
@ -460,7 +455,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
var policy = CreatePolicy(); var policy = CreatePolicy();
// Act // Act
await policy.ApplyAsync(httpContext, context, candidates); await policy.ApplyAsync(httpContext, candidates);
// Assert // Assert
Assert.True(candidates.IsValidCandidate(0)); Assert.True(candidates.IsValidCandidate(0));
@ -476,7 +471,6 @@ namespace Microsoft.AspNetCore.Mvc.Routing
}; };
var candidates = CreateCandidateSet(endpoints); var candidates = CreateCandidateSet(endpoints);
var context = new EndpointSelectorContext();
var httpContext = new DefaultHttpContext() var httpContext = new DefaultHttpContext()
{ {
Request = Request =
@ -488,7 +482,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
var policy = CreatePolicy(); var policy = CreatePolicy();
// Act // Act
await policy.ApplyAsync(httpContext, context, candidates); await policy.ApplyAsync(httpContext, candidates);
// Assert // Assert
Assert.True(candidates.IsValidCandidate(0)); Assert.True(candidates.IsValidCandidate(0));
@ -504,7 +498,6 @@ namespace Microsoft.AspNetCore.Mvc.Routing
}; };
var candidates = CreateCandidateSet(endpoints); var candidates = CreateCandidateSet(endpoints);
var context = new EndpointSelectorContext();
var httpContext = new DefaultHttpContext() var httpContext = new DefaultHttpContext()
{ {
Request = Request =
@ -516,7 +509,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
var policy = CreatePolicy(); var policy = CreatePolicy();
// Act // Act
await policy.ApplyAsync(httpContext, context, candidates); await policy.ApplyAsync(httpContext, candidates);
// Assert // Assert
Assert.True(candidates.IsValidCandidate(0)); Assert.True(candidates.IsValidCandidate(0));
@ -539,16 +532,15 @@ namespace Microsoft.AspNetCore.Mvc.Routing
ContentType = "application/json", ContentType = "application/json",
}, },
}; };
var context = new EndpointSelectorContext(httpContext);
var policy = CreatePolicy(); var policy = CreatePolicy();
// Act // Act
await policy.ApplyAsync(httpContext, context, candidates); await policy.ApplyAsync(httpContext, candidates);
// Assert // Assert
Assert.False(candidates.IsValidCandidate(0)); Assert.False(candidates.IsValidCandidate(0));
Assert.NotNull(context.Endpoint); Assert.NotNull(httpContext.GetEndpoint());
} }
[Fact] [Fact]
@ -569,16 +561,15 @@ namespace Microsoft.AspNetCore.Mvc.Routing
ContentType = "application/json", ContentType = "application/json",
}, },
}; };
var context = new EndpointSelectorContext(httpContext);
var policy = CreatePolicy(); var policy = CreatePolicy();
// Act // Act
await policy.ApplyAsync(httpContext, context, candidates); await policy.ApplyAsync(httpContext, candidates);
// Assert // Assert
Assert.False(candidates.IsValidCandidate(0)); Assert.False(candidates.IsValidCandidate(0));
Assert.Null(context.Endpoint); Assert.Null(httpContext.GetEndpoint());
} }
[Fact] [Fact]
@ -599,17 +590,16 @@ namespace Microsoft.AspNetCore.Mvc.Routing
ContentType = "application/json", ContentType = "application/json",
}, },
}; };
var context = new EndpointSelectorContext(httpContext);
var policy = CreatePolicy(); var policy = CreatePolicy();
// Act // Act
await policy.ApplyAsync(httpContext, context, candidates); await policy.ApplyAsync(httpContext, candidates);
// Assert // Assert
Assert.False(candidates.IsValidCandidate(0)); Assert.False(candidates.IsValidCandidate(0));
Assert.True(candidates.IsValidCandidate(1)); Assert.True(candidates.IsValidCandidate(1));
Assert.Null(context.Endpoint); Assert.Null(httpContext.GetEndpoint());
} }
private static RouteEndpoint CreateEndpoint(string template, ConsumesMetadata consumesMetadata, params object[] more) private static RouteEndpoint CreateEndpoint(string template, ConsumesMetadata consumesMetadata, params object[] more)

View File

@ -61,7 +61,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
return false; return false;
} }
public async Task ApplyAsync(HttpContext httpContext, EndpointSelectorContext context, CandidateSet candidates) public async Task ApplyAsync(HttpContext httpContext, CandidateSet candidates)
{ {
if (httpContext == null) if (httpContext == null)
{ {
@ -98,7 +98,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
// If there's no match this is a configuration error. We can't really check // If there's no match this is a configuration error. We can't really check
// during startup that the action you configured exists. // during startup that the action you configured exists.
throw new InvalidOperationException( throw new InvalidOperationException(
"Cannot find the fallback endpoint specified by route values: " + "Cannot find the fallback endpoint specified by route values: " +
"{ " + string.Join(", ", metadata.Values.Select(kvp => $"{kvp.Key}: {kvp.Value}")) + " }."); "{ " + string.Join(", ", metadata.Values.Select(kvp => $"{kvp.Key}: {kvp.Value}")) + " }.");
} }
@ -106,7 +106,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
var compiled = await _loader.LoadAsync(endpoints[0].Metadata.GetMetadata<PageActionDescriptor>()); var compiled = await _loader.LoadAsync(endpoints[0].Metadata.GetMetadata<PageActionDescriptor>());
var replacement = compiled.Endpoint; var replacement = compiled.Endpoint;
// We need to provide the route values associated with this endpoint, so that features // We need to provide the route values associated with this endpoint, so that features
// like URL generation work. // like URL generation work.
var values = new RouteValueDictionary(metadata.Values); var values = new RouteValueDictionary(metadata.Values);

View File

@ -51,7 +51,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
return false; return false;
} }
public Task ApplyAsync(HttpContext httpContext, EndpointSelectorContext context, CandidateSet candidates) public Task ApplyAsync(HttpContext httpContext, CandidateSet candidates)
{ {
if (httpContext == null) if (httpContext == null)
{ {

View File

@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
var policy = new PageLoaderMatcherPolicy(loader); var policy = new PageLoaderMatcherPolicy(loader);
// Act // Act
await policy.ApplyAsync(new DefaultHttpContext(), new EndpointSelectorContext(), candidateSet); await policy.ApplyAsync(new DefaultHttpContext(), candidateSet);
// Assert // Assert
Assert.Same(compiled.Endpoint, candidateSet[0].Endpoint); Assert.Same(compiled.Endpoint, candidateSet[0].Endpoint);
@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
var policy = new PageLoaderMatcherPolicy(loader); var policy = new PageLoaderMatcherPolicy(loader);
// Act // Act
var applyTask = policy.ApplyAsync(new DefaultHttpContext(), new EndpointSelectorContext(), candidateSet); var applyTask = policy.ApplyAsync(new DefaultHttpContext(), candidateSet);
tcs.SetResult(0); tcs.SetResult(0);
await applyTask; await applyTask;

View File

@ -34,7 +34,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
var selector = CreateSelector(actions); var selector = CreateSelector(actions);
// Act // Act
await selector.ApplyAsync(new DefaultHttpContext(), new EndpointSelectorContext(), candidateSet); await selector.ApplyAsync(new DefaultHttpContext(), candidateSet);
// Assert // Assert
Assert.True(candidateSet.IsValidCandidate(0)); Assert.True(candidateSet.IsValidCandidate(0));
@ -67,7 +67,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
var httpContext = CreateHttpContext("POST"); var httpContext = CreateHttpContext("POST");
// Act // Act
await selector.ApplyAsync(httpContext, new EndpointSelectorContext(), candidateSet); await selector.ApplyAsync(httpContext, candidateSet);
// Assert // Assert
Assert.True(candidateSet.IsValidCandidate(0)); Assert.True(candidateSet.IsValidCandidate(0));
@ -102,7 +102,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
var httpContext = CreateHttpContext("POST"); var httpContext = CreateHttpContext("POST");
// Act // Act
await selector.ApplyAsync(httpContext, new EndpointSelectorContext(), candidateSet); await selector.ApplyAsync(httpContext, candidateSet);
// Assert // Assert
Assert.False(candidateSet.IsValidCandidate(0)); Assert.False(candidateSet.IsValidCandidate(0));
@ -138,7 +138,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
var httpContext = CreateHttpContext("POST"); var httpContext = CreateHttpContext("POST");
// Act // Act
await selector.ApplyAsync(httpContext, new EndpointSelectorContext(), candidateSet); await selector.ApplyAsync(httpContext, candidateSet);
// Assert // Assert
Assert.False(candidateSet.IsValidCandidate(0)); Assert.False(candidateSet.IsValidCandidate(0));
@ -173,7 +173,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
var httpContext = CreateHttpContext("POST"); var httpContext = CreateHttpContext("POST");
// Act // Act
await selector.ApplyAsync(httpContext, new EndpointSelectorContext(), candidateSet); await selector.ApplyAsync(httpContext, candidateSet);
// Assert // Assert
Assert.True(candidateSet.IsValidCandidate(0)); Assert.True(candidateSet.IsValidCandidate(0));
@ -211,7 +211,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
var httpContext = CreateHttpContext("POST"); var httpContext = CreateHttpContext("POST");
// Act // Act
await selector.ApplyAsync(httpContext, new EndpointSelectorContext(), candidateSet); await selector.ApplyAsync(httpContext, candidateSet);
// Assert // Assert
Assert.False(candidateSet.IsValidCandidate(0)); Assert.False(candidateSet.IsValidCandidate(0));
@ -246,7 +246,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
var httpContext = CreateHttpContext("POST"); var httpContext = CreateHttpContext("POST");
// Act // Act
await selector.ApplyAsync(httpContext, new EndpointSelectorContext(), candidateSet); await selector.ApplyAsync(httpContext, candidateSet);
// Assert // Assert
Assert.False(candidateSet.IsValidCandidate(0)); Assert.False(candidateSet.IsValidCandidate(0));
@ -287,7 +287,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
var httpContext = CreateHttpContext("POST"); var httpContext = CreateHttpContext("POST");
// Act // Act
await selector.ApplyAsync(httpContext, new EndpointSelectorContext(), candidateSet); await selector.ApplyAsync(httpContext, candidateSet);
// Assert // Assert
Assert.True(candidateSet.IsValidCandidate(0)); Assert.True(candidateSet.IsValidCandidate(0));
@ -328,7 +328,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
var httpContext = CreateHttpContext("POST"); var httpContext = CreateHttpContext("POST");
// Act // Act
await selector.ApplyAsync(httpContext, new EndpointSelectorContext(), candidateSet); await selector.ApplyAsync(httpContext, candidateSet);
// Assert // Assert
Assert.True(candidateSet.IsValidCandidate(0)); Assert.True(candidateSet.IsValidCandidate(0));