Skip to content

Commit 28e21a9

Browse files
Handle ArgumentNullException within ApiVersionActionSelector when no actions are matched and return HTTP 404 instead. Fixes #52. (#56)
1 parent 2f3aa5b commit 28e21a9

23 files changed

+50
-19
lines changed

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

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
using System.Collections.Generic;
1414
using System.Diagnostics.Contracts;
1515
using System.Linq;
16-
using System.Threading.Tasks;
1716
using static ApiVersion;
1817
using static System.Environment;
1918
using static System.String;
@@ -24,6 +23,7 @@
2423
[CLSCompliant( false )]
2524
public class ApiVersionActionSelector : IActionSelector
2625
{
26+
private static readonly IReadOnlyList<ActionDescriptor> NoMatches = new ActionDescriptor[0];
2727
private readonly IActionSelectorDecisionTreeProvider decisionTreeProvider;
2828
private readonly ActionConstraintCache actionConstraintCache;
2929
private readonly IOptions<ApiVersioningOptions> options;
@@ -111,6 +111,7 @@ public virtual ActionDescriptor SelectBestCandidate( RouteContext context, IRead
111111
else if ( finalMatches.Count == 1 )
112112
{
113113
var selectedAction = finalMatches[0];
114+
selectedAction.AggregateAllVersions( selectionContext );
114115
httpContext.SetRequestedApiVersion( selectionContext.RequestedVersion );
115116
return selectedAction;
116117
}
@@ -172,16 +173,11 @@ where ActionIsSatisfiedBy( action, model, context.RequestedVersion, implicitMatc
172173
return bestMatches;
173174
}
174175

175-
var match = bestMatches[0];
176-
177-
if ( match.IsApiVersionNeutral() )
176+
if ( bestMatches[0].IsApiVersionNeutral() )
178177
{
179178
bestMatches.AddRange( implicitMatches );
180-
return bestMatches;
181179
}
182180

183-
match.AggregateAllVersions( context );
184-
185181
return bestMatches;
186182
}
187183

@@ -281,6 +277,7 @@ private IReadOnlyList<ActionDescriptor> EvaluateActionConstraints( RouteContext
281277
{
282278
Contract.Requires( context != null );
283279
Contract.Requires( actions != null );
280+
Contract.Ensures( Contract.Result<IReadOnlyList<ActionDescriptor>>() != null );
284281

285282
var candidates = new List<ActionSelectorCandidate>();
286283

@@ -292,22 +289,13 @@ private IReadOnlyList<ActionDescriptor> EvaluateActionConstraints( RouteContext
292289
}
293290

294291
var matches = EvaluateActionConstraintsCore( context, candidates, startingOrder: null );
295-
var results = default( List<ActionDescriptor> );
296292

297293
if ( matches == null )
298294
{
299-
return results;
300-
}
301-
302-
results = new List<ActionDescriptor>( matches.Count );
303-
304-
for ( var i = 0; i < matches.Count; i++ )
305-
{
306-
var candidate = matches[i];
307-
results.Add( candidate.Action );
295+
return NoMatches;
308296
}
309297

310-
return results;
298+
return matches.Select( candidate => candidate.Action ).ToArray();
311299
}
312300

313301
private IReadOnlyList<ActionSelectorCandidate> EvaluateActionConstraintsCore( RouteContext context, IReadOnlyList<ActionSelectorCandidate> candidates, int? startingOrder )

test/Microsoft.AspNetCore.Mvc.Acceptance.Tests/ByNamespace/Controllers/V1/AgreementsController.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
[ApiVersion( "1.0" )]
66
public class AgreementsController : Controller
77
{
8+
[HttpGet]
89
public IActionResult Get( string accountId ) => Ok( new Agreement( GetType().FullName, accountId, HttpContext.GetRequestedApiVersion().ToString() ) );
910
}
1011
}

test/Microsoft.AspNetCore.Mvc.Acceptance.Tests/ByNamespace/Controllers/V2/AgreementsController.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
[ApiVersion( "2.0" )]
66
public class AgreementsController : Controller
77
{
8+
[HttpGet]
89
public IActionResult Get( string accountId ) => Ok( new Agreement( GetType().FullName, accountId, HttpContext.GetRequestedApiVersion().ToString() ) );
910
}
1011
}

test/Microsoft.AspNetCore.Mvc.Acceptance.Tests/ByNamespace/Controllers/V3/AgreementsController.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
[ApiVersion( "3.0" )]
66
public class AgreementsController : Controller
77
{
8+
[HttpGet]
89
public IActionResult Get( string accountId ) => Ok( new Agreement( GetType().FullName, accountId, HttpContext.GetRequestedApiVersion().ToString() ) );
910
}
1011
}

test/Microsoft.AspNetCore.Mvc.Versioning.Tests/Simulators/AmbiguousController.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
[ApiVersion( "1.0" )]
77
public sealed class AmbiguousController : Controller
88
{
9+
[HttpGet]
910
public Task<string> Get() => Task.FromResult( "Test" );
1011
}
1112
}

test/Microsoft.AspNetCore.Mvc.Versioning.Tests/Simulators/AmbiguousNeutralController.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
[ControllerName( "Ambiguous" )]
88
public sealed class AmbiguousNeutralController : Controller
99
{
10+
[HttpGet]
1011
public Task<string> Get() => Task.FromResult( "Test" );
1112
}
1213
}

test/Microsoft.AspNetCore.Mvc.Versioning.Tests/Simulators/AmbiguousToo2Controller.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
[ControllerName( "AmbiguousToo" )]
88
public sealed class AmbiguousToo2Controller : Controller
99
{
10+
[HttpGet]
1011
public Task<string> Get() => Task.FromResult( "Test" );
1112
}
1213
}

test/Microsoft.AspNetCore.Mvc.Versioning.Tests/Simulators/AmbiguousTooController.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
[ApiVersion( "1.0" )]
77
public sealed class AmbiguousTooController : Controller
88
{
9+
[HttpGet]
910
public Task<string> Get() => Task.FromResult( "Test" );
1011
}
1112
}

test/Microsoft.AspNetCore.Mvc.Versioning.Tests/Simulators/ApiVersionedRoute2Controller.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
[Route( "api/v{version:apiVersion}/attributed" )]
99
public sealed class ApiVersionedRoute2Controller : Controller
1010
{
11+
[HttpGet]
1112
[MapToApiVersion( "4.0" )]
1213
public Task<string> GetV4() => Task.FromResult( "Test" );
13-
14+
15+
[HttpGet]
1416
public Task<string> Get() => Task.FromResult( "Test" );
1517
}
1618
}

test/Microsoft.AspNetCore.Mvc.Versioning.Tests/Simulators/ApiVersionedRouteController.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
[Route( "api/v{version:apiVersion}/attributed" )]
1010
public sealed class ApiVersionedRouteController : Controller
1111
{
12+
[HttpGet]
1213
public Task<string> Get() => Task.FromResult( "Test" );
1314
}
1415
}

0 commit comments

Comments
 (0)