Fix endpoint constraint cache (#555)

This commit is contained in:
James Newton-King 2018-06-13 16:40:06 +12:00 committed by GitHub
parent 6a6bd3f0da
commit 9efa7665c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 85 additions and 25 deletions

View File

@ -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 Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
@ -50,38 +51,48 @@ namespace Microsoft.AspNetCore.Routing.EndpointConstraints
return GetEndpointConstraintsFromEntry(entry, httpContext, endpoint); return GetEndpointConstraintsFromEntry(entry, httpContext, endpoint);
} }
if (endpoint.Metadata == null || endpoint.Metadata.Count == 0) List<EndpointConstraintItem> items = null;
if (endpoint.Metadata != null && endpoint.Metadata.Count > 0)
{ {
return null; items = endpoint.Metadata
.OfType<IEndpointConstraintMetadata>()
.Select(m => new EndpointConstraintItem(m))
.ToList();
} }
var items = endpoint.Metadata IReadOnlyList<IEndpointConstraint> endpointConstraints = null;
.OfType<IEndpointConstraintMetadata>()
.Select(m => new EndpointConstraintItem(m))
.ToList();
ExecuteProviders(httpContext, endpoint, items); if (items != null && items.Count > 0)
var endpointConstraints = ExtractEndpointConstraints(items);
var allEndpointConstraintsCached = true;
for (var i = 0; i < items.Count; i++)
{ {
var item = items[i]; ExecuteProviders(httpContext, endpoint, items);
if (!item.IsReusable)
endpointConstraints = ExtractEndpointConstraints(items);
var allEndpointConstraintsCached = true;
for (var i = 0; i < items.Count; i++)
{ {
item.Constraint = null; var item = items[i];
allEndpointConstraintsCached = false; if (!item.IsReusable)
{
item.Constraint = null;
allEndpointConstraintsCached = false;
}
} }
}
if (allEndpointConstraintsCached) if (allEndpointConstraintsCached)
{ {
entry = new CacheEntry(endpointConstraints); entry = new CacheEntry(endpointConstraints);
}
else
{
entry = new CacheEntry(items);
}
} }
else else
{ {
entry = new CacheEntry(items); // No constraints
entry = new CacheEntry();
} }
cache.Entries.TryAdd(endpoint, entry); cache.Entries.TryAdd(endpoint, entry);
@ -90,13 +101,17 @@ namespace Microsoft.AspNetCore.Routing.EndpointConstraints
private IReadOnlyList<IEndpointConstraint> GetEndpointConstraintsFromEntry(CacheEntry entry, HttpContext httpContext, Endpoint endpoint) private IReadOnlyList<IEndpointConstraint> GetEndpointConstraintsFromEntry(CacheEntry entry, HttpContext httpContext, Endpoint endpoint)
{ {
Debug.Assert(entry.EndpointConstraints != null || entry.Items != null);
if (entry.EndpointConstraints != null) if (entry.EndpointConstraints != null)
{ {
return entry.EndpointConstraints; return entry.EndpointConstraints;
} }
if (entry.Items == null)
{
// Endpoint has no constraints
return null;
}
var items = new List<EndpointConstraintItem>(entry.Items.Count); var items = new List<EndpointConstraintItem>(entry.Items.Count);
for (var i = 0; i < entry.Items.Count; i++) for (var i = 0; i < entry.Items.Count; i++)
{ {

View File

@ -210,6 +210,49 @@ namespace Microsoft.AspNetCore.Routing.EndpointConstraints
Assert.Same(action, actionWithConstraints); Assert.Same(action, actionWithConstraints);
} }
[Fact]
public void SelectBestCandidate_MultipleCallsNoConstraint_ReturnsEndpoint()
{
// Arrange
var noConstraint = new TestEndpoint(EndpointMetadataCollection.Empty, "noConstraint");
var actions = new Endpoint[] { noConstraint };
var selector = CreateSelector(actions);
var context = CreateHttpContext("POST");
// Act
var action1 = selector.SelectBestCandidate(context, actions);
var action2 = selector.SelectBestCandidate(context, actions);
// Assert
Assert.Same(action1, noConstraint);
Assert.Same(action2, noConstraint);
}
[Fact]
public void SelectBestCandidate_MultipleCallsNonConstraintMetadata_ReturnsEndpoint()
{
// Arrange
var noConstraint = new TestEndpoint(new EndpointMetadataCollection(new[]
{
new object(),
}), "noConstraint");
var actions = new Endpoint[] { noConstraint };
var selector = CreateSelector(actions);
var context = CreateHttpContext("POST");
// Act
var action1 = selector.SelectBestCandidate(context, actions);
var action2 = selector.SelectBestCandidate(context, actions);
// Assert
Assert.Same(action1, noConstraint);
Assert.Same(action2, noConstraint);
}
[Fact] [Fact]
public void SelectBestCandidate_EndpointConstraintFactory_ReturnsNull() public void SelectBestCandidate_EndpointConstraintFactory_ReturnsNull()
{ {
@ -225,10 +268,12 @@ namespace Microsoft.AspNetCore.Routing.EndpointConstraints
var context = CreateHttpContext("POST"); var context = CreateHttpContext("POST");
// Act // Act
var action = selector.SelectBestCandidate(context, actions); var action1 = selector.SelectBestCandidate(context, actions);
var action2 = selector.SelectBestCandidate(context, actions);
// Assert // Assert
Assert.Same(action, nullConstraint); Assert.Same(action1, nullConstraint);
Assert.Same(action2, nullConstraint);
} }
// There's a custom constraint provider registered that only understands BooleanConstraintMarker // There's a custom constraint provider registered that only understands BooleanConstraintMarker