Skip to content

Commit e239406

Browse files
Clear API versioning feature on reentry. Fixes #749. Resolves #748
1 parent 7478f65 commit e239406

File tree

3 files changed

+35
-9
lines changed

3 files changed

+35
-9
lines changed

src/Microsoft.AspNetCore.Mvc.Versioning/Versioning/ActionSelectionResult.cs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
[CLSCompliant( false )]
1212
public class ActionSelectionResult
1313
{
14-
readonly HashSet<ActionDescriptor> candidateActions = new HashSet<ActionDescriptor>();
15-
readonly HashSet<ActionDescriptor> matchingActions = new HashSet<ActionDescriptor>();
14+
HashSet<ActionDescriptor>? candidateActions;
15+
HashSet<ActionDescriptor>? matchingActions;
1616

1717
/// <summary>
1818
/// Gets the best action descriptor match.
@@ -21,21 +21,21 @@ public class ActionSelectionResult
2121
/// <remarks>This property returns the first occurrence of a single match in the earliest iteration. If
2222
/// no matches exist in any iteration or multiple matches exist, this property returns <c>null</c>.</remarks>
2323
[CLSCompliant( false )]
24-
public ActionDescriptor? BestMatch => MatchingActions.FirstOrDefault();
24+
public ActionDescriptor? BestMatch => matchingActions?.FirstOrDefault();
2525

2626
/// <summary>
2727
/// Gets a read-only collection of candidate actions.
2828
/// </summary>
2929
/// <value>A <see cref="IReadOnlyCollection{T}">read-only collection</see> of candidate <see cref="ActionDescriptor">actions</see>.</value>
3030
[CLSCompliant( false )]
31-
public IReadOnlyCollection<ActionDescriptor> CandidateActions => candidateActions;
31+
public IReadOnlyCollection<ActionDescriptor> CandidateActions => candidateActions ??= new();
3232

3333
/// <summary>
3434
/// Gets a read-only collection of matching actions.
3535
/// </summary>
3636
/// <value>A <see cref="IReadOnlyCollection{T}">read-only collection</see> of <see cref="ActionDescriptor">matching actions</see>.</value>
3737
[CLSCompliant( false )]
38-
public IReadOnlyCollection<ActionDescriptor> MatchingActions => matchingActions;
38+
public IReadOnlyCollection<ActionDescriptor> MatchingActions => matchingActions ??= new();
3939

4040
/// <summary>
4141
/// Adds the specified candidate actions to the selection result.
@@ -44,7 +44,7 @@ public class ActionSelectionResult
4444
/// to add to the selection result.</param>
4545
[CLSCompliant( false )]
4646
public void AddCandidates( IEnumerable<ActionDescriptor> actions ) =>
47-
candidateActions.AddRange( actions ?? throw new ArgumentNullException( nameof( actions ) ) );
47+
( candidateActions ??= new() ).AddRange( actions ?? throw new ArgumentNullException( nameof( actions ) ) );
4848

4949
/// <summary>
5050
/// Adds the specified matching actions to the selection result.
@@ -53,6 +53,16 @@ public void AddCandidates( IEnumerable<ActionDescriptor> actions ) =>
5353
/// to add to the selection result.</param>
5454
[CLSCompliant( false )]
5555
public void AddMatches( IEnumerable<ActionDescriptor> matches ) =>
56-
matchingActions.AddRange( matches ?? throw new ArgumentNullException( nameof( matches ) ) );
56+
( matchingActions ??= new() ).AddRange( matches ?? throw new ArgumentNullException( nameof( matches ) ) );
57+
58+
/// <summary>
59+
/// Clears the selection result.
60+
/// </summary>
61+
/// <remarks>The selection result should only ever be cleared if the routing middleware will be re-executed.</remarks>
62+
public void Clear()
63+
{
64+
candidateActions?.Clear();
65+
matchingActions?.Clear();
66+
}
5767
}
5868
}

src/Microsoft.AspNetCore.Mvc.Versioning/Versioning/ApiVersioningFeature.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public sealed class ApiVersioningFeature : IApiVersioningFeature
1313
readonly HttpContext context;
1414
string? rawApiVersion;
1515
ApiVersion? apiVersion;
16+
ActionSelectionResult? selectionResult;
1617

1718
/// <summary>
1819
/// Initializes a new instance of the <see cref="ApiVersioningFeature"/> class.
@@ -58,6 +59,6 @@ public ApiVersion? RequestedApiVersion
5859
}
5960

6061
/// <inheritdoc />
61-
public ActionSelectionResult SelectionResult { get; } = new ActionSelectionResult();
62+
public ActionSelectionResult SelectionResult => selectionResult ??= new();
6263
}
6364
}

src/Microsoft.AspNetCore.Mvc.Versioning/Versioning/ApiVersioningMiddleware.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,19 @@
33
namespace Microsoft.AspNetCore.Mvc.Versioning
44
{
55
using Microsoft.AspNetCore.Http;
6+
using Microsoft.Extensions.Options;
67
using System.Threading.Tasks;
78

89
sealed class ApiVersioningMiddleware
910
{
1011
readonly RequestDelegate next;
12+
readonly bool usingLegacyRouting;
1113

12-
public ApiVersioningMiddleware( RequestDelegate next ) => this.next = next;
14+
public ApiVersioningMiddleware( RequestDelegate next, IOptions<MvcOptions> options )
15+
{
16+
this.next = next;
17+
usingLegacyRouting = !options.Value.EnableEndpointRouting;
18+
}
1319

1420
public Task InvokeAsync( HttpContext context )
1521
{
@@ -20,6 +26,15 @@ public Task InvokeAsync( HttpContext context )
2026
feature = new ApiVersioningFeature( context );
2127
context.Features.Set( feature );
2228
}
29+
else
30+
{
31+
feature.RouteParameter = null;
32+
33+
if ( usingLegacyRouting )
34+
{
35+
feature.SelectionResult.Clear();
36+
}
37+
}
2338

2439
return next( context );
2540
}

0 commit comments

Comments
 (0)