Make endpoint routing allocation free in common scenarios (#9774)
- This change tries to remove the EndpointSelectoContext allocation by making it a wrapper struct over the HttpContext. Unlike before, the HttpContext gets mutated once any component in the routnig pipeline sets a non null endpoint. This used to happen after the processing was complete. - This change also implements the IRouteValuesFeature and IEndpointFeature in HttpProtocol to avoid the feature allocation and feature collection version churn. - We also set the IRouteValuesFeature in IRouter based scenarios. - Since we're not implementing IRoutingFeature in endpoint routing anymore we can just create the RouteData inside MVC. We do this by polyfilling RouteData when using endpoint routing inside of MVC - Implement GetRouteValue in terms of IRouteValuesFeature - Noop if the EndpointRoutingMiddleware if an endpoint is already set - Added tests
This commit is contained in:
parent
cc8af6d2c4
commit
0d77594d17
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
|
|
@ -23,8 +24,8 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
throw new ArgumentNullException(nameof(httpContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
var routingFeature = httpContext.Features[typeof(IRoutingFeature)] as IRoutingFeature;
|
var routingFeature = httpContext.Features.Get<IRoutingFeature>();
|
||||||
return routingFeature?.RouteData;
|
return routingFeature?.RouteData ?? new RouteData(httpContext.Request.RouteValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -46,8 +47,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
throw new ArgumentNullException(nameof(key));
|
throw new ArgumentNullException(nameof(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
var routingFeature = httpContext.Features[typeof(IRoutingFeature)] as IRoutingFeature;
|
return httpContext.Features.Get<IRouteValuesFeature>()?.RouteValues[key];
|
||||||
return routingFeature?.RouteData.Values[key];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,12 @@ using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Http.Features;
|
|
||||||
using Microsoft.AspNetCore.Routing.Matching;
|
using Microsoft.AspNetCore.Routing.Matching;
|
||||||
using Microsoft.AspNetCore.Routing.Patterns;
|
using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
using Microsoft.AspNetCore.Routing.Template;
|
using Microsoft.AspNetCore.Routing.Template;
|
||||||
using Microsoft.AspNetCore.Routing.Tree;
|
using Microsoft.AspNetCore.Routing.Tree;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
using Microsoft.Extensions.ObjectPool;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
|
|
@ -47,7 +45,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
return CreateServices().GetRequiredService<DfaMatcherBuilder>();
|
return CreateServices().GetRequiredService<DfaMatcherBuilder>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private protected static int[] SampleRequests(int endpointCount, int count)
|
private protected static int[] SampleRequests(int endpointCount, int count)
|
||||||
{
|
{
|
||||||
// This isn't very high tech, but it's at least regular distribution.
|
// This isn't very high tech, but it's at least regular distribution.
|
||||||
// We sort the route templates by precedence, so this should result in
|
// We sort the route templates by precedence, so this should result in
|
||||||
|
|
@ -131,12 +129,10 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
protected (HttpContext httpContext, RouteValueDictionary ambientValues) CreateCurrentRequestContext(
|
protected (HttpContext httpContext, RouteValueDictionary ambientValues) CreateCurrentRequestContext(
|
||||||
object ambientValues = null)
|
object ambientValues = null)
|
||||||
{
|
{
|
||||||
var feature = new EndpointSelectorContext { RouteValues = new RouteValueDictionary(ambientValues) };
|
|
||||||
var context = new DefaultHttpContext();
|
var context = new DefaultHttpContext();
|
||||||
context.Features.Set<IEndpointFeature>(feature);
|
context.Request.RouteValues = new RouteValueDictionary(ambientValues);
|
||||||
context.Features.Set<IRouteValuesFeature>(feature);
|
|
||||||
|
|
||||||
return (context, feature.RouteValues);
|
return (context, context.Request.RouteValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void CreateOutboundRouteEntry(TreeRouteBuilder treeRouteBuilder, RouteEndpoint endpoint)
|
protected void CreateOutboundRouteEntry(TreeRouteBuilder treeRouteBuilder, RouteEndpoint endpoint)
|
||||||
|
|
|
||||||
|
|
@ -11,15 +11,11 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
// Just like TechEmpower Plaintext
|
// Just like TechEmpower Plaintext
|
||||||
public partial class MatcherSingleEntryBenchmark : EndpointRoutingBenchmarkBase
|
public partial class MatcherSingleEntryBenchmark : EndpointRoutingBenchmarkBase
|
||||||
{
|
{
|
||||||
private const int SampleCount = 100;
|
|
||||||
|
|
||||||
private BarebonesMatcher _baseline;
|
private BarebonesMatcher _baseline;
|
||||||
private Matcher _dfa;
|
private Matcher _dfa;
|
||||||
private Matcher _route;
|
private Matcher _route;
|
||||||
private Matcher _tree;
|
private Matcher _tree;
|
||||||
|
|
||||||
private EndpointSelectorContext _feature;
|
|
||||||
|
|
||||||
[GlobalSetup]
|
[GlobalSetup]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
{
|
{
|
||||||
|
|
@ -35,8 +31,6 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
_dfa = SetupMatcher(CreateDfaMatcherBuilder());
|
_dfa = SetupMatcher(CreateDfaMatcherBuilder());
|
||||||
_route = SetupMatcher(new RouteMatcherBuilder());
|
_route = SetupMatcher(new RouteMatcherBuilder());
|
||||||
_tree = SetupMatcher(new TreeRouterMatcherBuilder());
|
_tree = SetupMatcher(new TreeRouterMatcherBuilder());
|
||||||
|
|
||||||
_feature = new EndpointSelectorContext();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Matcher SetupMatcher(MatcherBuilder builder)
|
private Matcher SetupMatcher(MatcherBuilder builder)
|
||||||
|
|
@ -48,8 +42,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
[Benchmark(Baseline = true)]
|
[Benchmark(Baseline = true)]
|
||||||
public async Task Baseline()
|
public async Task Baseline()
|
||||||
{
|
{
|
||||||
var feature = _feature;
|
|
||||||
var httpContext = Requests[0];
|
var httpContext = Requests[0];
|
||||||
|
var feature = new EndpointSelectorContext(httpContext);
|
||||||
|
|
||||||
await _baseline.MatchAsync(httpContext, feature);
|
await _baseline.MatchAsync(httpContext, feature);
|
||||||
Validate(httpContext, Endpoints[0], feature.Endpoint);
|
Validate(httpContext, Endpoints[0], feature.Endpoint);
|
||||||
|
|
@ -58,8 +52,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public async Task Dfa()
|
public async Task Dfa()
|
||||||
{
|
{
|
||||||
var feature = _feature;
|
|
||||||
var httpContext = Requests[0];
|
var httpContext = Requests[0];
|
||||||
|
var feature = new EndpointSelectorContext(httpContext);
|
||||||
|
|
||||||
await _dfa.MatchAsync(httpContext, feature);
|
await _dfa.MatchAsync(httpContext, feature);
|
||||||
Validate(httpContext, Endpoints[0], feature.Endpoint);
|
Validate(httpContext, Endpoints[0], feature.Endpoint);
|
||||||
|
|
@ -68,12 +62,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public async Task LegacyTreeRouter()
|
public async Task LegacyTreeRouter()
|
||||||
{
|
{
|
||||||
var feature = _feature;
|
|
||||||
|
|
||||||
var httpContext = Requests[0];
|
var httpContext = Requests[0];
|
||||||
|
var feature = new EndpointSelectorContext(httpContext);
|
||||||
// This is required to make the legacy router implementation work with global routing.
|
|
||||||
httpContext.Features.Set<IEndpointFeature>(feature);
|
|
||||||
|
|
||||||
await _tree.MatchAsync(httpContext, feature);
|
await _tree.MatchAsync(httpContext, feature);
|
||||||
Validate(httpContext, Endpoints[0], feature.Endpoint);
|
Validate(httpContext, Endpoints[0], feature.Endpoint);
|
||||||
|
|
@ -82,14 +72,11 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public async Task LegacyRouter()
|
public async Task LegacyRouter()
|
||||||
{
|
{
|
||||||
var feature = _feature;
|
|
||||||
var httpContext = Requests[0];
|
var httpContext = Requests[0];
|
||||||
|
var feature = new EndpointSelectorContext(httpContext);
|
||||||
// This is required to make the legacy router implementation work with global routing.
|
|
||||||
httpContext.Features.Set<IEndpointFeature>(feature);
|
|
||||||
|
|
||||||
await _route.MatchAsync(httpContext, feature);
|
await _route.MatchAsync(httpContext, feature);
|
||||||
Validate(httpContext, Endpoints[0], feature.Endpoint);
|
Validate(httpContext, Endpoints[0], feature.Endpoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -30,11 +30,6 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
throw new ArgumentNullException(nameof(httpContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
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))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -88,11 +88,12 @@ 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; } }
|
||||||
}
|
}
|
||||||
public sealed partial class EndpointSelectorContext : Microsoft.AspNetCore.Http.Features.IEndpointFeature, Microsoft.AspNetCore.Http.Features.IRouteValuesFeature, Microsoft.AspNetCore.Routing.IRoutingFeature
|
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
|
||||||
|
public readonly partial struct EndpointSelectorContext
|
||||||
{
|
{
|
||||||
public EndpointSelectorContext() { }
|
private readonly object _dummy;
|
||||||
public Microsoft.AspNetCore.Http.Endpoint Endpoint { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
public EndpointSelectorContext(Microsoft.AspNetCore.Http.HttpContext httpContext) { throw null; }
|
||||||
Microsoft.AspNetCore.Routing.RouteData Microsoft.AspNetCore.Routing.IRoutingFeature.RouteData { get { throw null; } set { } }
|
public Microsoft.AspNetCore.Http.Endpoint Endpoint { get { throw null; } set { } }
|
||||||
public Microsoft.AspNetCore.Routing.RouteValueDictionary RouteValues { 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)]
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ 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.Features;
|
|
||||||
using Microsoft.AspNetCore.Routing.Matching;
|
using Microsoft.AspNetCore.Routing.Matching;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
|
@ -56,7 +55,14 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
public Task Invoke(HttpContext httpContext)
|
public Task Invoke(HttpContext httpContext)
|
||||||
{
|
{
|
||||||
var feature = new EndpointSelectorContext();
|
var feature = new EndpointSelectorContext(httpContext);
|
||||||
|
|
||||||
|
// There's already an endpoint, skip maching completely
|
||||||
|
if (feature.Endpoint != null)
|
||||||
|
{
|
||||||
|
Log.MatchSkipped(_logger, feature.Endpoint);
|
||||||
|
return _next(httpContext);
|
||||||
|
}
|
||||||
|
|
||||||
// There's an inherent race condition between waiting for init and accessing the matcher
|
// There's an inherent race condition between waiting for init and accessing the matcher
|
||||||
// this is OK because once `_matcher` is initialized, it will not be set to null again.
|
// this is OK because once `_matcher` is initialized, it will not be set to null again.
|
||||||
|
|
@ -93,31 +99,19 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private Task SetRoutingAndContinue(HttpContext httpContext, EndpointSelectorContext feature)
|
private Task SetRoutingAndContinue(HttpContext httpContext, EndpointSelectorContext feature)
|
||||||
{
|
{
|
||||||
if (feature.Endpoint != null)
|
// If there was no mutation of the endpoint then log failure
|
||||||
{
|
if (feature.Endpoint is null)
|
||||||
// Set the endpoint feature only on success. This means we won't overwrite any
|
|
||||||
// existing state for related features unless we did something.
|
|
||||||
SetFeatures(httpContext, feature);
|
|
||||||
|
|
||||||
Log.MatchSuccess(_logger, feature);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
Log.MatchFailure(_logger);
|
Log.MatchFailure(_logger);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.MatchSuccess(_logger, feature);
|
||||||
|
}
|
||||||
|
|
||||||
return _next(httpContext);
|
return _next(httpContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetFeatures(HttpContext httpContext, EndpointSelectorContext context)
|
|
||||||
{
|
|
||||||
// For back-compat EndpointSelectorContext implements IEndpointFeature,
|
|
||||||
// IRouteValuesFeature and IRoutingFeature
|
|
||||||
httpContext.Features.Set<IRoutingFeature>(context);
|
|
||||||
httpContext.Features.Set<IRouteValuesFeature>(context);
|
|
||||||
httpContext.Features.Set<IEndpointFeature>(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
||||||
//
|
//
|
||||||
|
|
@ -185,6 +179,11 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
new EventId(2, "MatchFailure"),
|
new EventId(2, "MatchFailure"),
|
||||||
"Request did not match any endpoints");
|
"Request did not match any endpoints");
|
||||||
|
|
||||||
|
private static readonly Action<ILogger, string, Exception> _matchingSkipped = LoggerMessage.Define<string>(
|
||||||
|
LogLevel.Debug,
|
||||||
|
new EventId(3, "MatchingSkipped"),
|
||||||
|
"Endpoint '{EndpointName}' already set, skipping route matching.");
|
||||||
|
|
||||||
public static void MatchSuccess(ILogger logger, EndpointSelectorContext context)
|
public static void MatchSuccess(ILogger logger, EndpointSelectorContext context)
|
||||||
{
|
{
|
||||||
_matchSuccess(logger, context.Endpoint.DisplayName, null);
|
_matchSuccess(logger, context.Endpoint.DisplayName, null);
|
||||||
|
|
@ -194,6 +193,11 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
_matchFailure(logger, null);
|
_matchFailure(logger, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void MatchSkipped(ILogger logger, Endpoint endpoint)
|
||||||
|
{
|
||||||
|
_matchingSkipped(logger, endpoint.DisplayName, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,68 +3,49 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Http.Features;
|
using Microsoft.AspNetCore.Http.Endpoints;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
public sealed class EndpointSelectorContext : IEndpointFeature, IRouteValuesFeature, IRoutingFeature
|
public readonly struct EndpointSelectorContext
|
||||||
{
|
{
|
||||||
private RouteData _routeData;
|
private readonly HttpContext _httpContext;
|
||||||
private RouteValueDictionary _routeValues;
|
|
||||||
|
public EndpointSelectorContext(HttpContext httpContext)
|
||||||
|
{
|
||||||
|
_httpContext = httpContext ?? throw new ArgumentNullException(nameof(httpContext));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the selected <see cref="Http.Endpoint"/> for the current
|
/// Gets or sets the selected <see cref="Http.Endpoint"/> for the current
|
||||||
/// request.
|
/// request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Endpoint Endpoint { get; set; }
|
public Endpoint Endpoint
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _httpContext.GetEndpoint();
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_httpContext.SetEndpoint(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the <see cref="RouteValueDictionary"/> associated with the currrent
|
/// Gets or sets the <see cref="RouteValueDictionary"/> associated with the currrent
|
||||||
/// request.
|
/// request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public RouteValueDictionary RouteValues
|
public RouteValueDictionary RouteValues
|
||||||
{
|
|
||||||
get => _routeValues ?? (_routeValues = new RouteValueDictionary());
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_routeValues = value;
|
|
||||||
|
|
||||||
// RouteData will be created next get with new Values
|
|
||||||
_routeData = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the <see cref="RouteData"/> for the current request.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The setter is not implemented. Use <see cref="RouteValues"/> to set the route values.
|
|
||||||
/// </remarks>
|
|
||||||
RouteData IRoutingFeature.RouteData
|
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (_routeData == null)
|
return _httpContext.Request.RouteValues;
|
||||||
{
|
}
|
||||||
_routeData = _routeValues == null ? new RouteData() : new RouteData(_routeValues);
|
set
|
||||||
|
{
|
||||||
// Note: DataTokens won't update if someone else overwrites the Endpoint
|
_httpContext.Request.RouteValues = value;
|
||||||
// after route values has been set. This seems find since endpoints are a new
|
|
||||||
// feature and DataTokens are for back-compat.
|
|
||||||
var dataTokensMetadata = Endpoint?.Metadata.GetMetadata<IDataTokensMetadata>();
|
|
||||||
if (dataTokensMetadata != null)
|
|
||||||
{
|
|
||||||
var dataTokens = _routeData.DataTokens;
|
|
||||||
foreach (var kvp in dataTokensMetadata.DataTokens)
|
|
||||||
{
|
|
||||||
_routeData.DataTokens.Add(kvp.Key, kvp.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return _routeData;
|
|
||||||
}
|
}
|
||||||
set => throw new NotSupportedException();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,6 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
throw new ArgumentNullException(nameof(httpContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (candidateSet == null)
|
if (candidateSet == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(candidateSet));
|
throw new ArgumentNullException(nameof(candidateSet));
|
||||||
|
|
|
||||||
|
|
@ -34,11 +34,6 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
throw new ArgumentNullException(nameof(httpContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
// All of the logging we do here is at level debug, so we can get away with doing a single check.
|
// All of the logging we do here is at level debug, so we can get away with doing a single check.
|
||||||
var log = _logger.IsEnabled(LogLevel.Debug);
|
var log = _logger.IsEnabled(LogLevel.Debug);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,11 +77,6 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
throw new ArgumentNullException(nameof(httpContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (candidates == null)
|
if (candidates == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(candidates));
|
throw new ArgumentNullException(nameof(candidates));
|
||||||
|
|
|
||||||
|
|
@ -94,11 +94,6 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
throw new ArgumentNullException(nameof(httpContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (candidates == null)
|
if (candidates == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(candidates));
|
throw new ArgumentNullException(nameof(candidates));
|
||||||
|
|
|
||||||
|
|
@ -40,11 +40,15 @@ namespace Microsoft.AspNetCore.Builder
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
httpContext.Features[typeof(IRoutingFeature)] = new RoutingFeature()
|
var routingFeature = new RoutingFeature()
|
||||||
{
|
{
|
||||||
RouteData = context.RouteData,
|
RouteData = context.RouteData
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Set the RouteValues on the current request, this is to keep the IRouteValuesFeature inline with the IRoutingFeature
|
||||||
|
httpContext.Request.RouteValues = context.RouteData.Values;
|
||||||
|
httpContext.Features.Set<IRoutingFeature>(routingFeature);
|
||||||
|
|
||||||
await context.Handler(context.HttpContext);
|
await context.Handler(context.HttpContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -635,12 +635,8 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
var linkGenerator = CreateLinkGenerator(endpointControllerAction, endpointController, endpointEmpty, endpointControllerActionParameter);
|
var linkGenerator = CreateLinkGenerator(endpointControllerAction, endpointController, endpointEmpty, endpointControllerActionParameter);
|
||||||
|
|
||||||
var context = new EndpointSelectorContext()
|
|
||||||
{
|
|
||||||
RouteValues = new RouteValueDictionary(new { controller = "Home", action = "Index", })
|
|
||||||
};
|
|
||||||
var httpContext = CreateHttpContext();
|
var httpContext = CreateHttpContext();
|
||||||
httpContext.Features.Set<IRouteValuesFeature>(context);
|
httpContext.Request.RouteValues = new RouteValueDictionary(new { controller = "Home", action = "Index" });
|
||||||
|
|
||||||
var values = new RouteValueDictionary();
|
var values = new RouteValueDictionary();
|
||||||
for (int i = 0; i < routeNames.Length; i++)
|
for (int i = 0; i < routeNames.Length; i++)
|
||||||
|
|
@ -678,12 +674,8 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
var linkGenerator = CreateLinkGenerator(homeIndex, homeLogin);
|
var linkGenerator = CreateLinkGenerator(homeIndex, homeLogin);
|
||||||
|
|
||||||
var context = new EndpointSelectorContext()
|
|
||||||
{
|
|
||||||
RouteValues = new RouteValueDictionary(new { controller = "Home", action = "Index", })
|
|
||||||
};
|
|
||||||
var httpContext = CreateHttpContext();
|
var httpContext = CreateHttpContext();
|
||||||
httpContext.Features.Set<IRouteValuesFeature>(context);
|
httpContext.Request.RouteValues = new RouteValueDictionary(new { controller = "Home", action = "Index", });
|
||||||
|
|
||||||
var values = new RouteValueDictionary();
|
var values = new RouteValueDictionary();
|
||||||
for (int i = 0; i < routeNames.Length; i++)
|
for (int i = 0; i < routeNames.Length; i++)
|
||||||
|
|
@ -721,9 +713,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
var linkGenerator = CreateLinkGenerator(homeIndex, homeLogin);
|
var linkGenerator = CreateLinkGenerator(homeIndex, homeLogin);
|
||||||
|
|
||||||
var context = new EndpointSelectorContext();
|
|
||||||
var httpContext = CreateHttpContext();
|
var httpContext = CreateHttpContext();
|
||||||
httpContext.Features.Set<IRouteValuesFeature>(context);
|
|
||||||
|
|
||||||
var values = new RouteValueDictionary();
|
var values = new RouteValueDictionary();
|
||||||
for (int i = 0; i < routeNames.Length; i++)
|
for (int i = 0; i < routeNames.Length; i++)
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Cors.Infrastructure;
|
using Microsoft.AspNetCore.Cors.Infrastructure;
|
||||||
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.Extensions.Logging.Abstractions;
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
@ -44,12 +45,8 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
// Arrange
|
// Arrange
|
||||||
var httpContext = new DefaultHttpContext();
|
var httpContext = new DefaultHttpContext();
|
||||||
httpContext.RequestServices = new ServiceProvider();
|
httpContext.RequestServices = new ServiceProvider();
|
||||||
|
httpContext.SetEndpoint(null);
|
||||||
httpContext.Features.Set<IEndpointFeature>(new EndpointSelectorContext()
|
|
||||||
{
|
|
||||||
Endpoint = null,
|
|
||||||
});
|
|
||||||
|
|
||||||
RequestDelegate next = (c) =>
|
RequestDelegate next = (c) =>
|
||||||
{
|
{
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
|
@ -77,11 +74,8 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
};
|
};
|
||||||
|
|
||||||
httpContext.Features.Set<IEndpointFeature>(new EndpointSelectorContext()
|
httpContext.SetEndpoint(new Endpoint(endpointFunc, EndpointMetadataCollection.Empty, "Test"));
|
||||||
{
|
|
||||||
Endpoint = new Endpoint(endpointFunc, EndpointMetadataCollection.Empty, "Test"),
|
|
||||||
});
|
|
||||||
|
|
||||||
RequestDelegate next = (c) =>
|
RequestDelegate next = (c) =>
|
||||||
{
|
{
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
|
@ -108,10 +102,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
RequestServices = new ServiceProvider()
|
RequestServices = new ServiceProvider()
|
||||||
};
|
};
|
||||||
|
|
||||||
httpContext.Features.Set<IEndpointFeature>(new EndpointSelectorContext()
|
httpContext.SetEndpoint(new Endpoint(_ => Task.CompletedTask, new EndpointMetadataCollection(Mock.Of<IAuthorizeData>()), "Test"));
|
||||||
{
|
|
||||||
Endpoint = new Endpoint(_ => Task.CompletedTask, new EndpointMetadataCollection(Mock.Of<IAuthorizeData>()), "Test"),
|
|
||||||
});
|
|
||||||
|
|
||||||
var middleware = new EndpointMiddleware(NullLogger<EndpointMiddleware>.Instance, _ => Task.CompletedTask, RouteOptions);
|
var middleware = new EndpointMiddleware(NullLogger<EndpointMiddleware>.Instance, _ => Task.CompletedTask, RouteOptions);
|
||||||
|
|
||||||
|
|
@ -131,10 +122,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
RequestServices = new ServiceProvider()
|
RequestServices = new ServiceProvider()
|
||||||
};
|
};
|
||||||
|
|
||||||
httpContext.Features.Set<IEndpointFeature>(new EndpointSelectorContext()
|
httpContext.SetEndpoint(new Endpoint(_ => Task.CompletedTask, new EndpointMetadataCollection(Mock.Of<IAuthorizeData>()), "Test"));
|
||||||
{
|
|
||||||
Endpoint = new Endpoint(_ => Task.CompletedTask, new EndpointMetadataCollection(Mock.Of<IAuthorizeData>()), "Test"),
|
|
||||||
});
|
|
||||||
|
|
||||||
httpContext.Items[EndpointMiddleware.AuthorizationMiddlewareInvokedKey] = true;
|
httpContext.Items[EndpointMiddleware.AuthorizationMiddlewareInvokedKey] = true;
|
||||||
|
|
||||||
|
|
@ -155,10 +143,8 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
RequestServices = new ServiceProvider()
|
RequestServices = new ServiceProvider()
|
||||||
};
|
};
|
||||||
|
|
||||||
httpContext.Features.Set<IEndpointFeature>(new EndpointSelectorContext()
|
httpContext.SetEndpoint(new Endpoint(_ => Task.CompletedTask, new EndpointMetadataCollection(Mock.Of<IAuthorizeData>()), "Test"));
|
||||||
{
|
|
||||||
Endpoint = new Endpoint(_ => Task.CompletedTask, new EndpointMetadataCollection(Mock.Of<IAuthorizeData>()), "Test"),
|
|
||||||
});
|
|
||||||
var routeOptions = Options.Create(new RouteOptions { SuppressCheckForUnhandledSecurityMetadata = true });
|
var routeOptions = Options.Create(new RouteOptions { SuppressCheckForUnhandledSecurityMetadata = true });
|
||||||
var middleware = new EndpointMiddleware(NullLogger<EndpointMiddleware>.Instance, _ => Task.CompletedTask, routeOptions);
|
var middleware = new EndpointMiddleware(NullLogger<EndpointMiddleware>.Instance, _ => Task.CompletedTask, routeOptions);
|
||||||
|
|
||||||
|
|
@ -178,10 +164,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
RequestServices = new ServiceProvider()
|
RequestServices = new ServiceProvider()
|
||||||
};
|
};
|
||||||
|
|
||||||
httpContext.Features.Set<IEndpointFeature>(new EndpointSelectorContext()
|
httpContext.SetEndpoint(new Endpoint(_ => Task.CompletedTask, new EndpointMetadataCollection(Mock.Of<ICorsMetadata>()), "Test"));
|
||||||
{
|
|
||||||
Endpoint = new Endpoint(_ => Task.CompletedTask, new EndpointMetadataCollection(Mock.Of<ICorsMetadata>()), "Test"),
|
|
||||||
});
|
|
||||||
|
|
||||||
var middleware = new EndpointMiddleware(NullLogger<EndpointMiddleware>.Instance, _ => Task.CompletedTask, RouteOptions);
|
var middleware = new EndpointMiddleware(NullLogger<EndpointMiddleware>.Instance, _ => Task.CompletedTask, RouteOptions);
|
||||||
|
|
||||||
|
|
@ -201,10 +184,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
RequestServices = new ServiceProvider()
|
RequestServices = new ServiceProvider()
|
||||||
};
|
};
|
||||||
|
|
||||||
httpContext.Features.Set<IEndpointFeature>(new EndpointSelectorContext()
|
httpContext.SetEndpoint(new Endpoint(_ => Task.CompletedTask, new EndpointMetadataCollection(Mock.Of<ICorsMetadata>()), "Test"));
|
||||||
{
|
|
||||||
Endpoint = new Endpoint(_ => Task.CompletedTask, new EndpointMetadataCollection(Mock.Of<ICorsMetadata>()), "Test"),
|
|
||||||
});
|
|
||||||
|
|
||||||
httpContext.Items[EndpointMiddleware.CorsMiddlewareInvokedKey] = true;
|
httpContext.Items[EndpointMiddleware.CorsMiddlewareInvokedKey] = true;
|
||||||
|
|
||||||
|
|
@ -225,10 +205,8 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
RequestServices = new ServiceProvider()
|
RequestServices = new ServiceProvider()
|
||||||
};
|
};
|
||||||
|
|
||||||
httpContext.Features.Set<IEndpointFeature>(new EndpointSelectorContext()
|
httpContext.SetEndpoint(new Endpoint(_ => Task.CompletedTask, new EndpointMetadataCollection(Mock.Of<IAuthorizeData>()), "Test"));
|
||||||
{
|
|
||||||
Endpoint = new Endpoint(_ => Task.CompletedTask, new EndpointMetadataCollection(Mock.Of<IAuthorizeData>()), "Test"),
|
|
||||||
});
|
|
||||||
var routeOptions = Options.Create(new RouteOptions { SuppressCheckForUnhandledSecurityMetadata = true });
|
var routeOptions = Options.Create(new RouteOptions { SuppressCheckForUnhandledSecurityMetadata = true });
|
||||||
var middleware = new EndpointMiddleware(NullLogger<EndpointMiddleware>.Instance, _ => Task.CompletedTask, routeOptions);
|
var middleware = new EndpointMiddleware(NullLogger<EndpointMiddleware>.Instance, _ => Task.CompletedTask, routeOptions);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,16 @@
|
||||||
// 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;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
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;
|
||||||
using Microsoft.AspNetCore.Routing.TestObjects;
|
using Microsoft.AspNetCore.Routing.TestObjects;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
using Microsoft.Extensions.Logging.Testing;
|
using Microsoft.Extensions.Logging.Testing;
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -36,6 +35,24 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
Assert.NotNull(endpointFeature);
|
Assert.NotNull(endpointFeature);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Invoke_SkipsRouting_IfEndpointSet()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var httpContext = CreateHttpContext();
|
||||||
|
httpContext.SetEndpoint(new Endpoint(c => Task.CompletedTask, new EndpointMetadataCollection(), "myapp"));
|
||||||
|
|
||||||
|
var middleware = CreateMiddleware();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await middleware.Invoke(httpContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var endpoint = httpContext.GetEndpoint();
|
||||||
|
Assert.NotNull(endpoint);
|
||||||
|
Assert.Equal("myapp", endpoint.DisplayName);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Invoke_OnCall_WritesToConfiguredLogger()
|
public async Task Invoke_OnCall_WritesToConfiguredLogger()
|
||||||
{
|
{
|
||||||
|
|
@ -132,25 +149,22 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
private HttpContext CreateHttpContext()
|
private HttpContext CreateHttpContext()
|
||||||
{
|
{
|
||||||
var context = new EndpointSelectorContext();
|
var httpContext = new DefaultHttpContext
|
||||||
|
{
|
||||||
var httpContext = new DefaultHttpContext();
|
RequestServices = new TestServiceProvider()
|
||||||
httpContext.Features.Set<IEndpointFeature>(context);
|
};
|
||||||
httpContext.Features.Set<IRouteValuesFeature>(context);
|
|
||||||
|
|
||||||
httpContext.RequestServices = new TestServiceProvider();
|
|
||||||
|
|
||||||
return httpContext;
|
return httpContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
private EndpointRoutingMiddleware CreateMiddleware(
|
private EndpointRoutingMiddleware CreateMiddleware(
|
||||||
Logger<EndpointRoutingMiddleware> logger = null,
|
Logger<EndpointRoutingMiddleware> logger = null,
|
||||||
MatcherFactory matcherFactory = null)
|
MatcherFactory matcherFactory = null,
|
||||||
|
RequestDelegate next = null)
|
||||||
{
|
{
|
||||||
RequestDelegate next = (c) => Task.FromResult<object>(null);
|
next ??= c => Task.CompletedTask;
|
||||||
|
logger ??= new Logger<EndpointRoutingMiddleware>(NullLoggerFactory.Instance);
|
||||||
logger = logger ?? new Logger<EndpointRoutingMiddleware>(NullLoggerFactory.Instance);
|
matcherFactory ??= new TestMatcherFactory(true);
|
||||||
matcherFactory = matcherFactory ?? new TestMatcherFactory(true);
|
|
||||||
|
|
||||||
var middleware = new EndpointRoutingMiddleware(
|
var middleware = new EndpointRoutingMiddleware(
|
||||||
matcherFactory,
|
matcherFactory,
|
||||||
|
|
|
||||||
|
|
@ -1,9 +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 System.Linq;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Routing.Matching;
|
using Microsoft.AspNetCore.Http.Endpoints;
|
||||||
using Microsoft.AspNetCore.Routing.Patterns;
|
using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -12,48 +11,43 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
public class EndpointSelectorContextTest
|
public class EndpointSelectorContextTest
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public void RouteData_CanIntializeDataTokens_WithMetadata()
|
public void SettingEndpointSetsEndpointOnHttpContext()
|
||||||
{
|
{
|
||||||
// Arrange
|
var httpContext = new DefaultHttpContext();
|
||||||
var expected = new RouteValueDictionary(new { foo = 17, bar = "hello", });
|
var ep = new RouteEndpoint(
|
||||||
|
|
||||||
var context = new EndpointSelectorContext()
|
|
||||||
{
|
|
||||||
Endpoint = new RouteEndpoint(
|
|
||||||
TestConstants.EmptyRequestDelegate,
|
|
||||||
RoutePatternFactory.Parse("/"),
|
|
||||||
0,
|
|
||||||
new EndpointMetadataCollection(new DataTokensMetadata(expected)),
|
|
||||||
"test"),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var routeData = ((IRoutingFeature)context).RouteData;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.NotSame(expected, routeData.DataTokens);
|
|
||||||
Assert.Equal(expected.OrderBy(kvp => kvp.Key), routeData.DataTokens.OrderBy(kvp => kvp.Key));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void RouteData_DataTokensIsEmpty_WithoutMetadata()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var context = new EndpointSelectorContext()
|
|
||||||
{
|
|
||||||
Endpoint = new RouteEndpoint(
|
|
||||||
TestConstants.EmptyRequestDelegate,
|
TestConstants.EmptyRequestDelegate,
|
||||||
RoutePatternFactory.Parse("/"),
|
RoutePatternFactory.Parse("/"),
|
||||||
0,
|
0,
|
||||||
new EndpointMetadataCollection(),
|
new EndpointMetadataCollection(),
|
||||||
"test"),
|
"test");
|
||||||
|
|
||||||
|
new EndpointSelectorContext(httpContext)
|
||||||
|
{
|
||||||
|
Endpoint = ep,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
// Assert
|
||||||
var routeData = ((IRoutingFeature)context).RouteData;
|
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
|
||||||
Assert.Empty(routeData.DataTokens);
|
Assert.NotNull(httpContext.Request.RouteValues);
|
||||||
|
Assert.Same(routeValues, httpContext.Request.RouteValues);
|
||||||
|
Assert.Single(httpContext.Request.RouteValues);
|
||||||
|
Assert.Equal("1", httpContext.Request.RouteValues["A"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.Linq;
|
using System.Linq;
|
||||||
|
|
@ -26,12 +26,8 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
var linkGenerator = CreateLinkGenerator(endpoint1, endpoint2);
|
var linkGenerator = CreateLinkGenerator(endpoint1, endpoint2);
|
||||||
|
|
||||||
var context = new EndpointSelectorContext()
|
|
||||||
{
|
|
||||||
RouteValues = new RouteValueDictionary(new { p = "5", })
|
|
||||||
};
|
|
||||||
var httpContext = CreateHttpContext();
|
var httpContext = CreateHttpContext();
|
||||||
httpContext.Features.Set<IRouteValuesFeature>(context);
|
httpContext.Request.RouteValues = new RouteValueDictionary(new { p = "5", });
|
||||||
httpContext.Request.PathBase = new PathString("/Foo/Bar?encodeme?");
|
httpContext.Request.PathBase = new PathString("/Foo/Bar?encodeme?");
|
||||||
|
|
||||||
var values = new { query = "some?query", };
|
var values = new { query = "some?query", };
|
||||||
|
|
|
||||||
|
|
@ -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.Linq;
|
using System.Linq;
|
||||||
|
|
@ -32,12 +32,8 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
var linkGenerator = CreateLinkGenerator(endpoint1, endpoint2);
|
var linkGenerator = CreateLinkGenerator(endpoint1, endpoint2);
|
||||||
|
|
||||||
var context = new EndpointSelectorContext()
|
|
||||||
{
|
|
||||||
RouteValues = new RouteValueDictionary(new { action = "Index", })
|
|
||||||
};
|
|
||||||
var httpContext = CreateHttpContext();
|
var httpContext = CreateHttpContext();
|
||||||
httpContext.Features.Set<IRouteValuesFeature>(context);
|
httpContext.Request.RouteValues = new RouteValueDictionary(new { action = "Index", });
|
||||||
httpContext.Request.PathBase = new PathString("/Foo/Bar?encodeme?");
|
httpContext.Request.PathBase = new PathString("/Foo/Bar?encodeme?");
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
|
||||||
|
|
@ -18,14 +18,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
protected HttpContext CreateHttpContext(object ambientValues = null)
|
protected HttpContext CreateHttpContext(object ambientValues = null)
|
||||||
{
|
{
|
||||||
var httpContext = new DefaultHttpContext();
|
var httpContext = new DefaultHttpContext();
|
||||||
|
httpContext.Request.RouteValues = new RouteValueDictionary(ambientValues);
|
||||||
var context = new EndpointSelectorContext
|
|
||||||
{
|
|
||||||
RouteValues = new RouteValueDictionary(ambientValues)
|
|
||||||
};
|
|
||||||
|
|
||||||
httpContext.Features.Set<IEndpointFeature>(context);
|
|
||||||
httpContext.Features.Set<IRouteValuesFeature>(context);
|
|
||||||
return httpContext;
|
return httpContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -27,11 +27,6 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
throw new ArgumentNullException(nameof(httpContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
var path = httpContext.Request.Path.Value;
|
var path = httpContext.Request.Path.Value;
|
||||||
for (var i = 0; i < Matchers.Length; i++)
|
for (var i = 0; i < Matchers.Length; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -133,4 +128,4 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -174,12 +174,8 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
private static (HttpContext httpContext, EndpointSelectorContext context) CreateContext()
|
private static (HttpContext httpContext, EndpointSelectorContext context) CreateContext()
|
||||||
{
|
{
|
||||||
var context = new EndpointSelectorContext();
|
|
||||||
var httpContext = new DefaultHttpContext();
|
var httpContext = new DefaultHttpContext();
|
||||||
httpContext.Features.Set<IEndpointFeature>(context);
|
return (httpContext, new EndpointSelectorContext(httpContext));
|
||||||
httpContext.Features.Set<IRouteValuesFeature>(context);
|
|
||||||
|
|
||||||
return (httpContext, context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static RouteEndpoint CreateEndpoint(string template)
|
private static RouteEndpoint CreateEndpoint(string template)
|
||||||
|
|
|
||||||
|
|
@ -403,7 +403,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
var endpointSelector = new Mock<EndpointSelector>();
|
var endpointSelector = new Mock<EndpointSelector>();
|
||||||
endpointSelector
|
endpointSelector
|
||||||
.Setup(s => s.SelectAsync(It.IsAny<HttpContext>(), It.IsAny<EndpointSelectorContext>(), It.IsAny<CandidateSet>()))
|
.Setup(s => s.SelectAsync(It.IsAny<HttpContext>(), It.IsAny<EndpointSelectorContext>(), It.IsAny<CandidateSet>()))
|
||||||
.Callback<HttpContext, IEndpointFeature, CandidateSet>((c, f, cs) =>
|
.Callback<HttpContext, EndpointSelectorContext, CandidateSet>((c, f, cs) =>
|
||||||
{
|
{
|
||||||
Assert.Equal(2, cs.Count);
|
Assert.Equal(2, cs.Count);
|
||||||
|
|
||||||
|
|
@ -449,7 +449,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
var endpointSelector = new Mock<EndpointSelector>();
|
var endpointSelector = new Mock<EndpointSelector>();
|
||||||
endpointSelector
|
endpointSelector
|
||||||
.Setup(s => s.SelectAsync(It.IsAny<HttpContext>(), It.IsAny<EndpointSelectorContext>(), It.IsAny<CandidateSet>()))
|
.Setup(s => s.SelectAsync(It.IsAny<HttpContext>(), It.IsAny<EndpointSelectorContext>(), It.IsAny<CandidateSet>()))
|
||||||
.Callback<HttpContext, IEndpointFeature, CandidateSet>((c, f, cs) =>
|
.Callback<HttpContext, EndpointSelectorContext, CandidateSet>((c, f, cs) =>
|
||||||
{
|
{
|
||||||
Assert.Equal(2, cs.Count);
|
Assert.Equal(2, cs.Count);
|
||||||
|
|
||||||
|
|
@ -496,7 +496,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
var endpointSelector = new Mock<EndpointSelector>();
|
var endpointSelector = new Mock<EndpointSelector>();
|
||||||
endpointSelector
|
endpointSelector
|
||||||
.Setup(s => s.SelectAsync(It.IsAny<HttpContext>(), It.IsAny<EndpointSelectorContext>(), It.IsAny<CandidateSet>()))
|
.Setup(s => s.SelectAsync(It.IsAny<HttpContext>(), It.IsAny<EndpointSelectorContext>(), It.IsAny<CandidateSet>()))
|
||||||
.Callback<HttpContext, IEndpointFeature, CandidateSet>((c, f, cs) =>
|
.Callback<HttpContext, EndpointSelectorContext, CandidateSet>((c, f, cs) =>
|
||||||
{
|
{
|
||||||
Assert.Equal(2, cs.Count);
|
Assert.Equal(2, cs.Count);
|
||||||
|
|
||||||
|
|
@ -727,7 +727,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
var (httpContext, context) = CreateContext();
|
var (httpContext, context) = CreateContext();
|
||||||
httpContext.Request.Path = "/test/17";
|
httpContext.Request.Path = "/test/17";
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await matcher.MatchAsync(httpContext, context);
|
await matcher.MatchAsync(httpContext, context);
|
||||||
|
|
||||||
|
|
@ -821,13 +821,9 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
private (HttpContext httpContext, EndpointSelectorContext context) CreateContext()
|
private (HttpContext httpContext, EndpointSelectorContext context) CreateContext()
|
||||||
{
|
{
|
||||||
var context = new EndpointSelectorContext();
|
|
||||||
|
|
||||||
var httpContext = new DefaultHttpContext();
|
var httpContext = new DefaultHttpContext();
|
||||||
httpContext.Features.Set<IEndpointFeature>(context);
|
|
||||||
httpContext.Features.Set<IRouteValuesFeature>(context);
|
|
||||||
|
|
||||||
return (httpContext, context);
|
return (httpContext, new EndpointSelectorContext(httpContext));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -303,11 +303,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
httpContext.Request.Path = path;
|
httpContext.Request.Path = path;
|
||||||
httpContext.Request.Scheme = scheme;
|
httpContext.Request.Scheme = scheme;
|
||||||
|
|
||||||
var context = new EndpointSelectorContext();
|
return (httpContext, new EndpointSelectorContext(httpContext));
|
||||||
httpContext.Features.Set<IEndpointFeature>(context);
|
|
||||||
httpContext.Features.Set<IRouteValuesFeature>(context);
|
|
||||||
|
|
||||||
return (httpContext, context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal RouteEndpoint CreateEndpoint(
|
internal RouteEndpoint CreateEndpoint(
|
||||||
|
|
|
||||||
|
|
@ -352,11 +352,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
httpContext.Request.Headers[AccessControlRequestMethod] = httpMethod;
|
httpContext.Request.Headers[AccessControlRequestMethod] = httpMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
var context = new EndpointSelectorContext();
|
return (httpContext, new EndpointSelectorContext(httpContext));
|
||||||
httpContext.Features.Set<IEndpointFeature>(context);
|
|
||||||
httpContext.Features.Set<IRouteValuesFeature>(context);
|
|
||||||
|
|
||||||
return (httpContext, context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal RouteEndpoint CreateEndpoint(
|
internal RouteEndpoint CreateEndpoint(
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
throw new XunitException($"Was expected to match '{expected.DisplayName}' but did not match.");
|
throw new XunitException($"Was expected to match '{expected.DisplayName}' but did not match.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var actualValues = httpContext.Features.Get<IRouteValuesFeature>().RouteValues;
|
var actualValues = httpContext.Request.RouteValues;
|
||||||
|
|
||||||
if (actualValues == null)
|
if (actualValues == null)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -20,15 +20,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
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));
|
||||||
var context = new EndpointSelectorContext()
|
|
||||||
{
|
|
||||||
RouteValues = new RouteValueDictionary()
|
|
||||||
};
|
|
||||||
httpContext.Features.Set<IEndpointFeature>(context);
|
|
||||||
httpContext.Features.Set<IRouteValuesFeature>(context);
|
|
||||||
|
|
||||||
return (httpContext, context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The older routing implementations retrieve services when they first execute.
|
// The older routing implementations retrieve services when they first execute.
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -24,11 +24,6 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
throw new ArgumentNullException(nameof(httpContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
var routeContext = new RouteContext(httpContext);
|
var routeContext = new RouteContext(httpContext);
|
||||||
await _inner.RouteAsync(routeContext);
|
await _inner.RouteAsync(routeContext);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
// 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;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.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;
|
||||||
|
|
@ -95,10 +96,9 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
public async Task RouteAsync(RouteContext routeContext)
|
public async Task RouteAsync(RouteContext routeContext)
|
||||||
{
|
{
|
||||||
var context = (EndpointSelectorContext)routeContext.HttpContext.Features.Get<IEndpointFeature>();
|
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.
|
||||||
// across requests.
|
|
||||||
context.Endpoint = null;
|
context.Endpoint = null;
|
||||||
|
|
||||||
await _selector.SelectAsync(routeContext.HttpContext, context, new CandidateSet(_candidates, _values, _scores));
|
await _selector.SelectAsync(routeContext.HttpContext, context, new CandidateSet(_candidates, _values, _scores));
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -26,11 +26,6 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
throw new ArgumentNullException(nameof(httpContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
var routeContext = new RouteContext(httpContext);
|
var routeContext = new RouteContext(httpContext);
|
||||||
await _inner.RouteAsync(routeContext);
|
await _inner.RouteAsync(routeContext);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -99,11 +99,11 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
|
|
||||||
public async Task RouteAsync(RouteContext routeContext)
|
public async Task RouteAsync(RouteContext routeContext)
|
||||||
{
|
{
|
||||||
var context = (EndpointSelectorContext)routeContext.HttpContext.Features.Get<IEndpointFeature>();
|
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;
|
context.Endpoint = null;
|
||||||
|
|
||||||
await _selector.SelectAsync(routeContext.HttpContext, context, new CandidateSet(_candidates, _values, _scores));
|
await _selector.SelectAsync(routeContext.HttpContext, context, new CandidateSet(_candidates, _values, _scores));
|
||||||
if (context.Endpoint != null)
|
if (context.Endpoint != null)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,65 @@ using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
using Microsoft.Extensions.Logging.Testing;
|
using Microsoft.Extensions.Logging.Testing;
|
||||||
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
public class RouterMiddlewareTest
|
public class RouterMiddlewareTest
|
||||||
{
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task RoutingFeatureSetInIRouter()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var services = new ServiceCollection();
|
||||||
|
services.AddLogging();
|
||||||
|
var httpContext = new DefaultHttpContext
|
||||||
|
{
|
||||||
|
RequestServices = services.BuildServiceProvider()
|
||||||
|
};
|
||||||
|
|
||||||
|
httpContext.Request.Path = "/foo/10";
|
||||||
|
|
||||||
|
var routeHandlerExecuted = false;
|
||||||
|
|
||||||
|
var handler = new RouteHandler(context =>
|
||||||
|
{
|
||||||
|
routeHandlerExecuted = true;
|
||||||
|
|
||||||
|
var routingFeature = context.Features.Get<IRoutingFeature>();
|
||||||
|
|
||||||
|
Assert.NotNull(routingFeature);
|
||||||
|
Assert.NotNull(context.Features.Get<IRouteValuesFeature>());
|
||||||
|
|
||||||
|
Assert.Single(routingFeature.RouteData.Values);
|
||||||
|
Assert.Single(context.Request.RouteValues);
|
||||||
|
Assert.True(routingFeature.RouteData.Values.ContainsKey("id"));
|
||||||
|
Assert.True(context.Request.RouteValues.ContainsKey("id"));
|
||||||
|
Assert.Equal("10", routingFeature.RouteData.Values["id"]);
|
||||||
|
Assert.Equal("10", context.Request.RouteValues["id"]);
|
||||||
|
Assert.Equal("10", context.GetRouteValue("id"));
|
||||||
|
Assert.Same(routingFeature.RouteData, context.GetRouteData());
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
});
|
||||||
|
|
||||||
|
var route = new Route(handler, "/foo/{id}", Mock.Of<IInlineConstraintResolver>());
|
||||||
|
|
||||||
|
var middleware = new RouterMiddleware(context => Task.CompletedTask, NullLoggerFactory.Instance, route);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await middleware.Invoke(httpContext);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(routeHandlerExecuted);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Invoke_LogsCorrectValues_WhenNotHandled()
|
public async Task Invoke_LogsCorrectValues_WhenNotHandled()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -173,7 +173,7 @@ namespace RoutingWebSite
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
app.UseEndpoints(endpoints =>
|
app.UseEndpoints(endpoints =>
|
||||||
{
|
{
|
||||||
endpoints.MapGet("api/get/{id}", (context) => context.Response.WriteAsync($"{name} - API Get {context.GetRouteData().Values["id"]}"));
|
endpoints.MapGet("api/get/{id}", (context) => context.Response.WriteAsync($"{name} - API Get {context.Request.RouteValues["id"]}"));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -286,7 +286,9 @@ namespace Microsoft.AspNetCore.Mvc.Routing
|
||||||
|
|
||||||
RequestDelegate requestDelegate = (context) =>
|
RequestDelegate requestDelegate = (context) =>
|
||||||
{
|
{
|
||||||
var routeData = context.GetRouteData();
|
var routeData = new RouteData();
|
||||||
|
routeData.PushState(router: null, context.Request.RouteValues, dataTokens);
|
||||||
|
|
||||||
var actionContext = new ActionContext(context, routeData, action);
|
var actionContext = new ActionContext(context, routeData, action);
|
||||||
|
|
||||||
if (invokerFactory == null)
|
if (invokerFactory == null)
|
||||||
|
|
|
||||||
|
|
@ -60,11 +60,6 @@ namespace Microsoft.AspNetCore.Mvc.Routing
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
throw new ArgumentNullException(nameof(httpContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (candidates == null)
|
if (candidates == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(candidates));
|
throw new ArgumentNullException(nameof(candidates));
|
||||||
|
|
|
||||||
|
|
@ -66,12 +66,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
throw new ArgumentNullException(nameof(httpContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (candidates == null)
|
if (candidates == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(candidates));
|
throw new ArgumentNullException(nameof(candidates));
|
||||||
|
|
|
||||||
|
|
@ -532,7 +532,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 =
|
||||||
|
|
@ -540,6 +539,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
|
||||||
ContentType = "application/json",
|
ContentType = "application/json",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
var context = new EndpointSelectorContext(httpContext);
|
||||||
|
|
||||||
var policy = CreatePolicy();
|
var policy = CreatePolicy();
|
||||||
|
|
||||||
|
|
@ -562,7 +562,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 =
|
||||||
|
|
@ -570,6 +569,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
|
||||||
ContentType = "application/json",
|
ContentType = "application/json",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
var context = new EndpointSelectorContext(httpContext);
|
||||||
|
|
||||||
var policy = CreatePolicy();
|
var policy = CreatePolicy();
|
||||||
|
|
||||||
|
|
@ -592,7 +592,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 =
|
||||||
|
|
@ -600,6 +599,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
|
||||||
ContentType = "application/json",
|
ContentType = "application/json",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
var context = new EndpointSelectorContext(httpContext);
|
||||||
|
|
||||||
var policy = CreatePolicy();
|
var policy = CreatePolicy();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -209,14 +209,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
private HttpContext CreateHttpContext(object ambientValues = null)
|
private HttpContext CreateHttpContext(object ambientValues = null)
|
||||||
{
|
{
|
||||||
var httpContext = new DefaultHttpContext();
|
var httpContext = new DefaultHttpContext();
|
||||||
|
httpContext.Request.RouteValues = new RouteValueDictionary(ambientValues);
|
||||||
var feature = new EndpointSelectorContext
|
|
||||||
{
|
|
||||||
RouteValues = new RouteValueDictionary(ambientValues)
|
|
||||||
};
|
|
||||||
|
|
||||||
httpContext.Features.Set<IEndpointFeature>(feature);
|
|
||||||
httpContext.Features.Set<IRouteValuesFeature>(feature);
|
|
||||||
return httpContext;
|
return httpContext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
using Microsoft.AspNetCore.Routing;
|
||||||
using Microsoft.AspNetCore.Routing.Matching;
|
using Microsoft.AspNetCore.Routing.Matching;
|
||||||
|
|
@ -59,12 +60,8 @@ namespace Microsoft.AspNetCore.Mvc.Routing
|
||||||
routeName: "OrdersApi");
|
routeName: "OrdersApi");
|
||||||
var urlHelper = CreateUrlHelper(new[] { endpoint1, endpoint2 });
|
var urlHelper = CreateUrlHelper(new[] { endpoint1, endpoint2 });
|
||||||
|
|
||||||
// Set the endpoint feature and current context just as a normal request to MVC app would be
|
urlHelper.ActionContext.HttpContext.SetEndpoint(endpoint1);
|
||||||
var endpointFeature = new EndpointSelectorContext();
|
urlHelper.ActionContext.HttpContext.Request.RouteValues = new RouteValueDictionary
|
||||||
urlHelper.ActionContext.HttpContext.Features.Set<IEndpointFeature>(endpointFeature);
|
|
||||||
urlHelper.ActionContext.HttpContext.Features.Set<IRouteValuesFeature>(endpointFeature);
|
|
||||||
endpointFeature.Endpoint = endpoint1;
|
|
||||||
endpointFeature.RouteValues = new RouteValueDictionary
|
|
||||||
{
|
{
|
||||||
["controller"] = "Orders",
|
["controller"] = "Orders",
|
||||||
["action"] = "GetById",
|
["action"] = "GetById",
|
||||||
|
|
@ -149,13 +146,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
|
||||||
protected override IUrlHelper CreateUrlHelper(ActionContext actionContext)
|
protected override IUrlHelper CreateUrlHelper(ActionContext actionContext)
|
||||||
{
|
{
|
||||||
var httpContext = actionContext.HttpContext;
|
var httpContext = actionContext.HttpContext;
|
||||||
httpContext.Features.Set<IEndpointFeature>(new EndpointSelectorContext()
|
httpContext.SetEndpoint(new Endpoint(context => Task.CompletedTask, EndpointMetadataCollection.Empty, null));
|
||||||
{
|
|
||||||
Endpoint = new Endpoint(
|
|
||||||
context => Task.CompletedTask,
|
|
||||||
EndpointMetadataCollection.Empty,
|
|
||||||
null)
|
|
||||||
});
|
|
||||||
|
|
||||||
var urlHelperFactory = httpContext.RequestServices.GetRequiredService<IUrlHelperFactory>();
|
var urlHelperFactory = httpContext.RequestServices.GetRequiredService<IUrlHelperFactory>();
|
||||||
var urlHelper = urlHelperFactory.GetUrlHelper(actionContext);
|
var urlHelper = urlHelperFactory.GetUrlHelper(actionContext);
|
||||||
|
|
|
||||||
|
|
@ -207,14 +207,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
private HttpContext CreateHttpContext(object ambientValues = null)
|
private HttpContext CreateHttpContext(object ambientValues = null)
|
||||||
{
|
{
|
||||||
var httpContext = new DefaultHttpContext();
|
var httpContext = new DefaultHttpContext();
|
||||||
|
httpContext.Request.RouteValues = new RouteValueDictionary(ambientValues);
|
||||||
var feature = new EndpointSelectorContext
|
|
||||||
{
|
|
||||||
RouteValues = new RouteValueDictionary(ambientValues)
|
|
||||||
};
|
|
||||||
|
|
||||||
httpContext.Features.Set<IEndpointFeature>(feature);
|
|
||||||
httpContext.Features.Set<IRouteValuesFeature>(feature);
|
|
||||||
return httpContext;
|
return httpContext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,11 +68,6 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
throw new ArgumentNullException(nameof(httpContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (candidates == null)
|
if (candidates == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(candidates));
|
throw new ArgumentNullException(nameof(candidates));
|
||||||
|
|
|
||||||
|
|
@ -58,11 +58,6 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
||||||
throw new ArgumentNullException(nameof(httpContext));
|
throw new ArgumentNullException(nameof(httpContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (candidates == null)
|
if (candidates == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(candidates));
|
throw new ArgumentNullException(nameof(candidates));
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Http.Features;
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
using Microsoft.AspNetCore.Routing;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
|
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
|
||||||
|
|
@ -18,16 +19,18 @@ using Microsoft.Net.Http.Headers;
|
||||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
{
|
{
|
||||||
internal partial class HttpProtocol : IHttpRequestFeature,
|
internal partial class HttpProtocol : IHttpRequestFeature,
|
||||||
IHttpResponseFeature,
|
IHttpResponseFeature,
|
||||||
IResponseBodyPipeFeature,
|
IResponseBodyPipeFeature,
|
||||||
IRequestBodyPipeFeature,
|
IRequestBodyPipeFeature,
|
||||||
IHttpUpgradeFeature,
|
IHttpUpgradeFeature,
|
||||||
IHttpConnectionFeature,
|
IHttpConnectionFeature,
|
||||||
IHttpRequestLifetimeFeature,
|
IHttpRequestLifetimeFeature,
|
||||||
IHttpRequestIdentifierFeature,
|
IHttpRequestIdentifierFeature,
|
||||||
IHttpBodyControlFeature,
|
IHttpBodyControlFeature,
|
||||||
IHttpMaxRequestBodySizeFeature,
|
IHttpMaxRequestBodySizeFeature,
|
||||||
IHttpResponseStartFeature
|
IHttpResponseStartFeature,
|
||||||
|
IEndpointFeature,
|
||||||
|
IRouteValuesFeature
|
||||||
{
|
{
|
||||||
// NOTE: When feature interfaces are added to or removed from this HttpProtocol class implementation,
|
// NOTE: When feature interfaces are added to or removed from this HttpProtocol class implementation,
|
||||||
// then the list of `implementedFeatures` in the generated code project MUST also be updated.
|
// then the list of `implementedFeatures` in the generated code project MUST also be updated.
|
||||||
|
|
@ -258,6 +261,18 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Endpoint IEndpointFeature.Endpoint
|
||||||
|
{
|
||||||
|
get => _endpoint;
|
||||||
|
set => _endpoint = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
RouteValueDictionary IRouteValuesFeature.RouteValues
|
||||||
|
{
|
||||||
|
get => _routeValues ??= new RouteValueDictionary();
|
||||||
|
set => _routeValues = value;
|
||||||
|
}
|
||||||
|
|
||||||
protected void ResetHttp1Features()
|
protected void ResetHttp1Features()
|
||||||
{
|
{
|
||||||
_currentIHttpMinRequestBodyDataRateFeature = this;
|
_currentIHttpMinRequestBodyDataRateFeature = this;
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
private static readonly Type IServiceProvidersFeatureType = typeof(IServiceProvidersFeature);
|
private static readonly Type IServiceProvidersFeatureType = typeof(IServiceProvidersFeature);
|
||||||
private static readonly Type IHttpRequestLifetimeFeatureType = typeof(IHttpRequestLifetimeFeature);
|
private static readonly Type IHttpRequestLifetimeFeatureType = typeof(IHttpRequestLifetimeFeature);
|
||||||
private static readonly Type IHttpConnectionFeatureType = typeof(IHttpConnectionFeature);
|
private static readonly Type IHttpConnectionFeatureType = typeof(IHttpConnectionFeature);
|
||||||
|
private static readonly Type IRouteValuesFeatureType = typeof(IRouteValuesFeature);
|
||||||
|
private static readonly Type IEndpointFeatureType = typeof(IEndpointFeature);
|
||||||
private static readonly Type IHttpAuthenticationFeatureType = typeof(IHttpAuthenticationFeature);
|
private static readonly Type IHttpAuthenticationFeatureType = typeof(IHttpAuthenticationFeature);
|
||||||
private static readonly Type IQueryFeatureType = typeof(IQueryFeature);
|
private static readonly Type IQueryFeatureType = typeof(IQueryFeature);
|
||||||
private static readonly Type IFormFeatureType = typeof(IFormFeature);
|
private static readonly Type IFormFeatureType = typeof(IFormFeature);
|
||||||
|
|
@ -47,6 +49,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
private object _currentIServiceProvidersFeature;
|
private object _currentIServiceProvidersFeature;
|
||||||
private object _currentIHttpRequestLifetimeFeature;
|
private object _currentIHttpRequestLifetimeFeature;
|
||||||
private object _currentIHttpConnectionFeature;
|
private object _currentIHttpConnectionFeature;
|
||||||
|
private object _currentIRouteValuesFeature;
|
||||||
|
private object _currentIEndpointFeature;
|
||||||
private object _currentIHttpAuthenticationFeature;
|
private object _currentIHttpAuthenticationFeature;
|
||||||
private object _currentIQueryFeature;
|
private object _currentIQueryFeature;
|
||||||
private object _currentIFormFeature;
|
private object _currentIFormFeature;
|
||||||
|
|
@ -82,6 +86,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
_currentIHttpMaxRequestBodySizeFeature = this;
|
_currentIHttpMaxRequestBodySizeFeature = this;
|
||||||
_currentIHttpBodyControlFeature = this;
|
_currentIHttpBodyControlFeature = this;
|
||||||
_currentIHttpResponseStartFeature = this;
|
_currentIHttpResponseStartFeature = this;
|
||||||
|
_currentIRouteValuesFeature = this;
|
||||||
|
_currentIEndpointFeature = this;
|
||||||
|
|
||||||
_currentIServiceProvidersFeature = null;
|
_currentIServiceProvidersFeature = null;
|
||||||
_currentIHttpAuthenticationFeature = null;
|
_currentIHttpAuthenticationFeature = null;
|
||||||
|
|
@ -183,6 +189,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
{
|
{
|
||||||
feature = _currentIHttpConnectionFeature;
|
feature = _currentIHttpConnectionFeature;
|
||||||
}
|
}
|
||||||
|
else if (key == IRouteValuesFeatureType)
|
||||||
|
{
|
||||||
|
feature = _currentIRouteValuesFeature;
|
||||||
|
}
|
||||||
|
else if (key == IEndpointFeatureType)
|
||||||
|
{
|
||||||
|
feature = _currentIEndpointFeature;
|
||||||
|
}
|
||||||
else if (key == IHttpAuthenticationFeatureType)
|
else if (key == IHttpAuthenticationFeatureType)
|
||||||
{
|
{
|
||||||
feature = _currentIHttpAuthenticationFeature;
|
feature = _currentIHttpAuthenticationFeature;
|
||||||
|
|
@ -295,6 +309,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
{
|
{
|
||||||
_currentIHttpConnectionFeature = value;
|
_currentIHttpConnectionFeature = value;
|
||||||
}
|
}
|
||||||
|
else if (key == IRouteValuesFeatureType)
|
||||||
|
{
|
||||||
|
_currentIRouteValuesFeature = value;
|
||||||
|
}
|
||||||
|
else if (key == IEndpointFeatureType)
|
||||||
|
{
|
||||||
|
_currentIEndpointFeature = value;
|
||||||
|
}
|
||||||
else if (key == IHttpAuthenticationFeatureType)
|
else if (key == IHttpAuthenticationFeatureType)
|
||||||
{
|
{
|
||||||
_currentIHttpAuthenticationFeature = value;
|
_currentIHttpAuthenticationFeature = value;
|
||||||
|
|
@ -405,6 +427,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
{
|
{
|
||||||
feature = (TFeature)_currentIHttpConnectionFeature;
|
feature = (TFeature)_currentIHttpConnectionFeature;
|
||||||
}
|
}
|
||||||
|
else if (typeof(TFeature) == typeof(IRouteValuesFeature))
|
||||||
|
{
|
||||||
|
feature = (TFeature)_currentIRouteValuesFeature;
|
||||||
|
}
|
||||||
|
else if (typeof(TFeature) == typeof(IEndpointFeature))
|
||||||
|
{
|
||||||
|
feature = (TFeature)_currentIEndpointFeature;
|
||||||
|
}
|
||||||
else if (typeof(TFeature) == typeof(IHttpAuthenticationFeature))
|
else if (typeof(TFeature) == typeof(IHttpAuthenticationFeature))
|
||||||
{
|
{
|
||||||
feature = (TFeature)_currentIHttpAuthenticationFeature;
|
feature = (TFeature)_currentIHttpAuthenticationFeature;
|
||||||
|
|
@ -521,6 +551,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
{
|
{
|
||||||
_currentIHttpConnectionFeature = feature;
|
_currentIHttpConnectionFeature = feature;
|
||||||
}
|
}
|
||||||
|
else if (typeof(TFeature) == typeof(IRouteValuesFeature))
|
||||||
|
{
|
||||||
|
_currentIRouteValuesFeature = feature;
|
||||||
|
}
|
||||||
|
else if (typeof(TFeature) == typeof(IEndpointFeature))
|
||||||
|
{
|
||||||
|
_currentIEndpointFeature = feature;
|
||||||
|
}
|
||||||
else if (typeof(TFeature) == typeof(IHttpAuthenticationFeature))
|
else if (typeof(TFeature) == typeof(IHttpAuthenticationFeature))
|
||||||
{
|
{
|
||||||
_currentIHttpAuthenticationFeature = feature;
|
_currentIHttpAuthenticationFeature = feature;
|
||||||
|
|
@ -629,6 +667,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpConnectionFeatureType, _currentIHttpConnectionFeature);
|
yield return new KeyValuePair<Type, object>(IHttpConnectionFeatureType, _currentIHttpConnectionFeature);
|
||||||
}
|
}
|
||||||
|
if (_currentIRouteValuesFeature != null)
|
||||||
|
{
|
||||||
|
yield return new KeyValuePair<Type, object>(IRouteValuesFeatureType, _currentIRouteValuesFeature);
|
||||||
|
}
|
||||||
|
if (_currentIEndpointFeature != null)
|
||||||
|
{
|
||||||
|
yield return new KeyValuePair<Type, object>(IEndpointFeatureType, _currentIEndpointFeature);
|
||||||
|
}
|
||||||
if (_currentIHttpAuthenticationFeature != null)
|
if (_currentIHttpAuthenticationFeature != null)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<Type, object>(IHttpAuthenticationFeatureType, _currentIHttpAuthenticationFeature);
|
yield return new KeyValuePair<Type, object>(IHttpAuthenticationFeatureType, _currentIHttpAuthenticationFeature);
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ using Microsoft.AspNetCore.Hosting.Server;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Http.Features;
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Internal;
|
using Microsoft.AspNetCore.Internal;
|
||||||
|
using Microsoft.AspNetCore.Routing;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
|
|
@ -64,6 +65,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
|
|
||||||
private readonly HttpConnectionContext _context;
|
private readonly HttpConnectionContext _context;
|
||||||
private DefaultHttpContext _httpContext;
|
private DefaultHttpContext _httpContext;
|
||||||
|
private RouteValueDictionary _routeValues;
|
||||||
|
private Endpoint _endpoint;
|
||||||
|
|
||||||
protected string _methodText = null;
|
protected string _methodText = null;
|
||||||
private string _scheme = null;
|
private string _scheme = null;
|
||||||
|
|
@ -326,6 +329,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
{
|
{
|
||||||
_onStarting?.Clear();
|
_onStarting?.Clear();
|
||||||
_onCompleted?.Clear();
|
_onCompleted?.Clear();
|
||||||
|
_routeValues?.Clear();
|
||||||
|
|
||||||
_requestProcessingStatus = RequestProcessingStatus.RequestPending;
|
_requestProcessingStatus = RequestProcessingStatus.RequestPending;
|
||||||
_autoChunk = false;
|
_autoChunk = false;
|
||||||
|
|
@ -340,6 +344,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
TraceIdentifier = null;
|
TraceIdentifier = null;
|
||||||
Method = HttpMethod.None;
|
Method = HttpMethod.None;
|
||||||
_methodText = null;
|
_methodText = null;
|
||||||
|
_endpoint = null;
|
||||||
PathBase = null;
|
PathBase = null;
|
||||||
Path = null;
|
Path = null;
|
||||||
RawTarget = null;
|
RawTarget = null;
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
_collection[typeof(IHttpMinResponseDataRateFeature)] = CreateHttp1Connection();
|
_collection[typeof(IHttpMinResponseDataRateFeature)] = CreateHttp1Connection();
|
||||||
_collection[typeof(IHttpBodyControlFeature)] = CreateHttp1Connection();
|
_collection[typeof(IHttpBodyControlFeature)] = CreateHttp1Connection();
|
||||||
_collection[typeof(IHttpResponseStartFeature)] = CreateHttp1Connection();
|
_collection[typeof(IHttpResponseStartFeature)] = CreateHttp1Connection();
|
||||||
|
_collection[typeof(IRouteValuesFeature)] = CreateHttp1Connection();
|
||||||
|
_collection[typeof(IEndpointFeature)] = CreateHttp1Connection();
|
||||||
|
|
||||||
CompareGenericGetterToIndexer();
|
CompareGenericGetterToIndexer();
|
||||||
|
|
||||||
|
|
@ -148,6 +150,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
_collection.Set<IHttpMinResponseDataRateFeature>(CreateHttp1Connection());
|
_collection.Set<IHttpMinResponseDataRateFeature>(CreateHttp1Connection());
|
||||||
_collection.Set<IHttpBodyControlFeature>(CreateHttp1Connection());
|
_collection.Set<IHttpBodyControlFeature>(CreateHttp1Connection());
|
||||||
_collection.Set<IHttpResponseStartFeature>(CreateHttp1Connection());
|
_collection.Set<IHttpResponseStartFeature>(CreateHttp1Connection());
|
||||||
|
_collection.Set<IRouteValuesFeature>(CreateHttp1Connection());
|
||||||
|
_collection.Set<IEndpointFeature>(CreateHttp1Connection());
|
||||||
|
|
||||||
CompareGenericGetterToIndexer();
|
CompareGenericGetterToIndexer();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ namespace CodeGenerator
|
||||||
"IServiceProvidersFeature",
|
"IServiceProvidersFeature",
|
||||||
"IHttpRequestLifetimeFeature",
|
"IHttpRequestLifetimeFeature",
|
||||||
"IHttpConnectionFeature",
|
"IHttpConnectionFeature",
|
||||||
|
"IRouteValuesFeature",
|
||||||
|
"IEndpointFeature"
|
||||||
};
|
};
|
||||||
|
|
||||||
var commonFeatures = new[]
|
var commonFeatures = new[]
|
||||||
|
|
@ -70,7 +72,9 @@ namespace CodeGenerator
|
||||||
"IHttpConnectionFeature",
|
"IHttpConnectionFeature",
|
||||||
"IHttpMaxRequestBodySizeFeature",
|
"IHttpMaxRequestBodySizeFeature",
|
||||||
"IHttpBodyControlFeature",
|
"IHttpBodyControlFeature",
|
||||||
"IHttpResponseStartFeature"
|
"IHttpResponseStartFeature",
|
||||||
|
"IRouteValuesFeature",
|
||||||
|
"IEndpointFeature"
|
||||||
};
|
};
|
||||||
|
|
||||||
var usings = $@"
|
var usings = $@"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue