Lazy create EndpointRouting statemachines (#9506)
This commit is contained in:
parent
507a765dfb
commit
23efa15112
|
|
@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
_routeOptions = routeOptions?.Value ?? throw new ArgumentNullException(nameof(routeOptions));
|
_routeOptions = routeOptions?.Value ?? throw new ArgumentNullException(nameof(routeOptions));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Invoke(HttpContext httpContext)
|
public Task Invoke(HttpContext httpContext)
|
||||||
{
|
{
|
||||||
var endpoint = httpContext.Features.Get<IEndpointFeature>()?.Endpoint;
|
var endpoint = httpContext.Features.Get<IEndpointFeature>()?.Endpoint;
|
||||||
if (endpoint?.RequestDelegate != null)
|
if (endpoint?.RequestDelegate != null)
|
||||||
|
|
@ -39,7 +39,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
if (_routeOptions.SuppressCheckForUnhandledSecurityMetadata)
|
if (_routeOptions.SuppressCheckForUnhandledSecurityMetadata)
|
||||||
{
|
{
|
||||||
// User opted out of this check.
|
// User opted out of this check.
|
||||||
return;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (endpoint.Metadata.GetMetadata<IAuthorizeData>() != null &&
|
if (endpoint.Metadata.GetMetadata<IAuthorizeData>() != null &&
|
||||||
|
|
@ -58,17 +58,35 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await endpoint.RequestDelegate(httpContext);
|
var requestTask = endpoint.RequestDelegate(httpContext);
|
||||||
|
if (!requestTask.IsCompletedSuccessfully)
|
||||||
|
{
|
||||||
|
return AwaitRequestTask(endpoint, requestTask, _logger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
Log.ExecutedEndpoint(_logger, endpoint);
|
||||||
|
return Task.FromException(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.ExecutedEndpoint(_logger, endpoint);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _next(httpContext);
|
||||||
|
|
||||||
|
static async Task AwaitRequestTask(Endpoint endpoint, Task requestTask, ILogger logger)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await requestTask;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
Log.ExecutedEndpoint(_logger, endpoint);
|
Log.ExecutedEndpoint(logger, endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await _next(httpContext);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ThrowMissingAuthMiddlewareException(Endpoint endpoint)
|
private static void ThrowMissingAuthMiddlewareException(Endpoint endpoint)
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
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;
|
||||||
|
|
@ -53,15 +54,45 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
_endpointDataSource = new CompositeEndpointDataSource(endpointRouteBuilder.DataSources);
|
_endpointDataSource = new CompositeEndpointDataSource(endpointRouteBuilder.DataSources);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Invoke(HttpContext httpContext)
|
public Task Invoke(HttpContext httpContext)
|
||||||
{
|
{
|
||||||
var feature = new EndpointSelectorContext();
|
var feature = new EndpointSelectorContext();
|
||||||
|
|
||||||
// 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.
|
||||||
var matcher = await InitializeAsync();
|
var matcherTask = InitializeAsync();
|
||||||
|
if (!matcherTask.IsCompletedSuccessfully)
|
||||||
|
{
|
||||||
|
return AwaitMatcher(this, httpContext, feature, matcherTask);
|
||||||
|
}
|
||||||
|
|
||||||
await matcher.MatchAsync(httpContext, feature);
|
var matchTask = matcherTask.Result.MatchAsync(httpContext, feature);
|
||||||
|
if (!matchTask.IsCompletedSuccessfully)
|
||||||
|
{
|
||||||
|
return AwaitMatch(this, httpContext, feature, matchTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SetRoutingAndContinue(httpContext, feature);
|
||||||
|
|
||||||
|
// Awaited fallbacks for when the Tasks do not synchronously complete
|
||||||
|
static async Task AwaitMatcher(EndpointRoutingMiddleware middleware, HttpContext httpContext, EndpointSelectorContext feature, Task<Matcher> matcherTask)
|
||||||
|
{
|
||||||
|
var matcher = await matcherTask;
|
||||||
|
await matcher.MatchAsync(httpContext, feature);
|
||||||
|
await middleware.SetRoutingAndContinue(httpContext, feature);
|
||||||
|
}
|
||||||
|
|
||||||
|
static async Task AwaitMatch(EndpointRoutingMiddleware middleware, HttpContext httpContext, EndpointSelectorContext feature, Task matchTask)
|
||||||
|
{
|
||||||
|
await matchTask;
|
||||||
|
await middleware.SetRoutingAndContinue(httpContext, feature);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private Task SetRoutingAndContinue(HttpContext httpContext, EndpointSelectorContext feature)
|
||||||
|
{
|
||||||
if (feature.Endpoint != null)
|
if (feature.Endpoint != null)
|
||||||
{
|
{
|
||||||
// Set the endpoint feature only on success. This means we won't overwrite any
|
// Set the endpoint feature only on success. This means we won't overwrite any
|
||||||
|
|
@ -75,7 +106,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
Log.MatchFailure(_logger);
|
Log.MatchFailure(_logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
await _next(httpContext);
|
return _next(httpContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetFeatures(HttpContext httpContext, EndpointSelectorContext context)
|
private static void SetFeatures(HttpContext httpContext, EndpointSelectorContext context)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue