Skip to content

Commit a9c46c1

Browse files
Restore functionality to report versions when unmatched. Fixes #876. Fixes #918.
1 parent 4c53a86 commit a9c46c1

File tree

34 files changed

+338
-144
lines changed

34 files changed

+338
-144
lines changed

Diff for: src/AspNet/Acceptance/Asp.Versioning.WebApi.Acceptance.Tests/Http/Basic/given a versioned ApiController/when using a query string and split into two types.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public async Task then_get_should_return_200( string controller, string apiVersi
3434
}
3535

3636
[Fact]
37-
public async Task then_get_should_return_404_for_an_unsupported_version()
37+
public async Task then_get_should_return_400_for_an_unsupported_version()
3838
{
3939
// arrange
4040

@@ -44,7 +44,7 @@ public async Task then_get_should_return_404_for_an_unsupported_version()
4444
var problem = await response.Content.ReadAsProblemDetailsAsync();
4545

4646
// assert
47-
response.StatusCode.Should().Be( NotFound );
47+
response.StatusCode.Should().Be( BadRequest );
4848
problem.Type.Should().Be( ProblemDetailsDefaults.Unsupported.Type );
4949
}
5050

Diff for: src/AspNet/Acceptance/Asp.Versioning.WebApi.Acceptance.Tests/Http/UsingConventions/given a versioned ApiController using conventions/when using a query string and split into two types.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public async Task then_get_should_return_200( string controller, string apiVersi
3535
}
3636

3737
[Fact]
38-
public async Task then_get_should_return_404_for_an_unsupported_version()
38+
public async Task then_get_should_return_400_for_an_unsupported_version()
3939
{
4040
// arrange
4141

@@ -45,7 +45,7 @@ public async Task then_get_should_return_404_for_an_unsupported_version()
4545
var problem = await response.Content.ReadAsProblemDetailsAsync();
4646

4747
// assert
48-
response.StatusCode.Should().Be( NotFound );
48+
response.StatusCode.Should().Be( BadRequest );
4949
problem.Type.Should().Be( ProblemDetailsDefaults.Unsupported.Type );
5050
}
5151

Diff for: src/AspNet/Acceptance/Asp.Versioning.WebApi.Acceptance.Tests/Http/UsingNamespace/given a versioned ApiController per namespace/when using a query string.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public async Task then_get_should_return_200( Type controllerType, string apiVer
3232
}
3333

3434
[Fact]
35-
public async Task then_get_should_return_404_for_an_unsupported_version()
35+
public async Task then_get_should_return_400_for_an_unsupported_version()
3636
{
3737
// arrange
3838

@@ -42,7 +42,7 @@ public async Task then_get_should_return_404_for_an_unsupported_version()
4242
var problem = await response.Content.ReadAsProblemDetailsAsync();
4343

4444
// assert
45-
response.StatusCode.Should().Be( NotFound );
45+
response.StatusCode.Should().Be( BadRequest );
4646
problem.Type.Should().Be( ProblemDetailsDefaults.Unsupported.Type );
4747
}
4848

Diff for: src/AspNet/Acceptance/Asp.Versioning.WebApi.Acceptance.Tests/OData/Advanced/given a versioned ODataController mixed with Web API controllers/when people is any version.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace given_a_versioned_ODataController_mixed_with_Web_API_controllers;
99
public class when_people_is_any_version : AdvancedAcceptanceTest
1010
{
1111
[Fact]
12-
public async Task then_patch_should_return_404_for_an_unsupported_version()
12+
public async Task then_patch_should_return_400_for_an_unsupported_version()
1313
{
1414
// arrange
1515
var person = new { lastName = "Me" };
@@ -19,7 +19,7 @@ public async Task then_patch_should_return_404_for_an_unsupported_version()
1919
var problem = await response.Content.ReadAsProblemDetailsAsync();
2020

2121
// assert
22-
response.StatusCode.Should().Be( NotFound );
22+
response.StatusCode.Should().Be( BadRequest );
2323
problem.Type.Should().Be( ProblemDetailsDefaults.Unsupported.Type );
2424
}
2525

Diff for: src/AspNet/Acceptance/Asp.Versioning.WebApi.Acceptance.Tests/OData/Basic/given a versioned ODataController/when using a query string and split into two types.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public async Task then_get_should_return_200( string requestUrl )
2828
}
2929

3030
[Fact]
31-
public async Task then_get_should_return_404_for_an_unsupported_version()
31+
public async Task then_get_should_return_400_for_an_unsupported_version()
3232
{
3333
// arrange
3434

@@ -38,7 +38,7 @@ public async Task then_get_should_return_404_for_an_unsupported_version()
3838
var problem = await response.Content.ReadAsProblemDetailsAsync();
3939

4040
// assert
41-
response.StatusCode.Should().Be( NotFound );
41+
response.StatusCode.Should().Be( BadRequest );
4242
problem.Type.Should().Be( ProblemDetailsDefaults.Unsupported.Type );
4343
}
4444

@@ -73,7 +73,7 @@ public async Task then_patch_should_return_405_if_supported_in_any_version( stri
7373
}
7474

7575
[Fact]
76-
public async Task then_patch_should_return_404_for_an_unsupported_version()
76+
public async Task then_patch_should_return_400_for_an_unsupported_version()
7777
{
7878
// arrange
7979
var person = new { id = 42, firstName = "John", lastName = "Doe", email = "[email protected]" };
@@ -83,7 +83,7 @@ public async Task then_patch_should_return_404_for_an_unsupported_version()
8383
var problem = await response.Content.ReadAsProblemDetailsAsync();
8484

8585
// assert
86-
response.StatusCode.Should().Be( NotFound );
86+
response.StatusCode.Should().Be( BadRequest );
8787
problem.Type.Should().Be( ProblemDetailsDefaults.Unsupported.Type );
8888
}
8989

Diff for: src/AspNet/Acceptance/Asp.Versioning.WebApi.Acceptance.Tests/OData/Basic/given a versioned ODataController/when using a query string.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public async Task then_get_should_return_200( string requestUrl )
2424
}
2525

2626
[Fact]
27-
public async Task then_get_should_return_404_for_an_unsupported_version()
27+
public async Task then_get_should_return_400_for_an_unsupported_version()
2828
{
2929
// arrange
3030

@@ -34,7 +34,7 @@ public async Task then_get_should_return_404_for_an_unsupported_version()
3434
var problem = await response.Content.ReadAsProblemDetailsAsync();
3535

3636
// assert
37-
response.StatusCode.Should().Be( NotFound );
37+
response.StatusCode.Should().Be( BadRequest );
3838
problem.Type.Should().Be( ProblemDetailsDefaults.Unsupported.Type );
3939
}
4040

Diff for: src/AspNet/Acceptance/Asp.Versioning.WebApi.Acceptance.Tests/OData/ODataAcceptanceTest.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public async Task then_the_service_document_should_be_versionX2Dspecific( string
3737
}
3838

3939
[Fact]
40-
public async Task then_the_service_document_should_return_404_for_an_unsupported_version()
40+
public async Task then_the_service_document_should_return_400_for_an_unsupported_version()
4141
{
4242
// arrange
4343

@@ -47,7 +47,7 @@ public async Task then_the_service_document_should_return_404_for_an_unsupported
4747
var problem = await response.Content.ReadAsProblemDetailsAsync();
4848

4949
// assert
50-
response.StatusCode.Should().Be( NotFound );
50+
response.StatusCode.Should().Be( BadRequest );
5151
problem.Type.Should().Be( ProblemDetailsDefaults.Unsupported.Type );
5252
}
5353

@@ -83,7 +83,7 @@ public async Task then_X24metadata_should_be_versionX2Dspecific( string apiVersi
8383
}
8484

8585
[Fact]
86-
public async Task then_X24metadata_should_return_404_for_an_unsupported_version()
86+
public async Task then_X24metadata_should_return_400_for_an_unsupported_version()
8787
{
8888
// arrange
8989
Client.DefaultRequestHeaders.Clear();
@@ -93,7 +93,7 @@ public async Task then_X24metadata_should_return_404_for_an_unsupported_version(
9393
var problem = await response.Content.ReadAsProblemDetailsAsync();
9494

9595
// assert
96-
response.StatusCode.Should().Be( NotFound );
96+
response.StatusCode.Should().Be( BadRequest );
9797
problem.Type.Should().Be( ProblemDetailsDefaults.Unsupported.Type );
9898
}
9999

Diff for: src/AspNet/Acceptance/Asp.Versioning.WebApi.Acceptance.Tests/OData/UsingConventions/given a versioned ODataController using conventions/when using a query string and split into two types.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public async Task then_get_should_return_200( string requestUrl )
2828
}
2929

3030
[Fact]
31-
public async Task then_get_should_return_404_for_an_unsupported_version()
31+
public async Task then_get_should_return_400_for_an_unsupported_version()
3232
{
3333
// arrange
3434

@@ -38,7 +38,7 @@ public async Task then_get_should_return_404_for_an_unsupported_version()
3838
var problem = await response.Content.ReadAsProblemDetailsAsync();
3939

4040
// assert
41-
response.StatusCode.Should().Be( NotFound );
41+
response.StatusCode.Should().Be( BadRequest );
4242
problem.Type.Should().Be( ProblemDetailsDefaults.Unsupported.Type );
4343
}
4444

@@ -73,7 +73,7 @@ public async Task then_patch_should_return_405_if_supported_in_any_version( stri
7373
}
7474

7575
[Fact]
76-
public async Task then_patch_should_return_404_for_an_unsupported_version()
76+
public async Task then_patch_should_return_400_for_an_unsupported_version()
7777
{
7878
// arrange
7979
var person = new { id = 42, firstName = "John", lastName = "Doe", email = "[email protected]" };
@@ -83,7 +83,7 @@ public async Task then_patch_should_return_404_for_an_unsupported_version()
8383
var problem = await response.Content.ReadAsProblemDetailsAsync();
8484

8585
// assert
86-
response.StatusCode.Should().Be( NotFound );
86+
response.StatusCode.Should().Be( BadRequest );
8787
problem.Type.Should().Be( ProblemDetailsDefaults.Unsupported.Type );
8888
}
8989

Diff for: src/AspNet/Acceptance/Asp.Versioning.WebApi.Acceptance.Tests/OData/UsingConventions/given a versioned ODataController using conventions/when using a query string.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public async Task then_get_should_return_200( string requestUrl )
2424
}
2525

2626
[Fact]
27-
public async Task then_get_should_return_404_for_an_unsupported_version()
27+
public async Task then_get_should_return_400_for_an_unsupported_version()
2828
{
2929
// arrange
3030

@@ -34,7 +34,7 @@ public async Task then_get_should_return_404_for_an_unsupported_version()
3434
var problem = await response.Content.ReadAsProblemDetailsAsync();
3535

3636
// assert
37-
response.StatusCode.Should().Be( NotFound );
37+
response.StatusCode.Should().Be( BadRequest );
3838
problem.Type.Should().Be( ProblemDetailsDefaults.Unsupported.Type );
3939
}
4040

Diff for: src/AspNet/WebApi/src/Asp.Versioning.WebApi/Dispatcher/HttpResponseExceptionFactory.cs

+24-6
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ namespace Asp.Versioning.Dispatcher;
99
using System.Web.Http.Tracing;
1010
using static System.Net.HttpStatusCode;
1111

12-
#pragma warning disable CA2000 // Dispose objects before losing scope
13-
1412
internal sealed class HttpResponseExceptionFactory
1513
{
1614
private const string Allow = nameof( Allow );
@@ -64,7 +62,8 @@ internal HttpResponseException NewUnmatchedException(
6462
}
6563
}
6664

67-
var versionsOnlyByMediaType = Options.ApiVersionReader.VersionsByMediaType( allowMultipleLocations: false );
65+
var options = Options;
66+
var versionsOnlyByMediaType = options.ApiVersionReader.VersionsByMediaType( allowMultipleLocations: false );
6867

6968
if ( versionsOnlyByMediaType )
7069
{
@@ -75,9 +74,28 @@ internal HttpResponseException NewUnmatchedException(
7574
if ( couldMatch )
7675
{
7776
properties ??= request.ApiVersionProperties();
78-
response = properties.RequestedApiVersion is ApiVersion apiVersion
79-
? CreateResponseForUnsupportedApiVersion( apiVersion, NotFound )
80-
: CreateNotFound( conventionRouteResult );
77+
78+
if ( properties.RequestedApiVersion is ApiVersion apiVersion )
79+
{
80+
HttpStatusCode statusCode;
81+
var matchedUrlSegment = !string.IsNullOrEmpty( properties.RouteParameter );
82+
83+
if ( matchedUrlSegment )
84+
{
85+
statusCode = NotFound;
86+
}
87+
else
88+
{
89+
var versionsByUrlOnly = options.ApiVersionReader.VersionsByUrl( allowMultipleLocations: false );
90+
statusCode = versionsByUrlOnly ? NotFound : options.UnsupportedApiVersionStatusCode;
91+
}
92+
93+
response = CreateResponseForUnsupportedApiVersion( apiVersion, statusCode );
94+
}
95+
else
96+
{
97+
response = CreateNotFound( conventionRouteResult );
98+
}
8199
}
82100
else
83101
{

Diff for: src/AspNet/WebApi/test/Asp.Versioning.WebApi.Tests/Dispatcher/ApiVersionControllerSelectorTest.cs

+8-8
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ public void select_controller_should_return_correct_versionX2DneutralX2C_convent
163163
}
164164

165165
[Fact]
166-
public async Task select_controller_should_return_404_for_unmatchedX2C_attributeX2Dbased_controller_version()
166+
public async Task select_controller_should_return_400_for_unmatchedX2C_attributeX2Dbased_controller_version()
167167
{
168168
// arrange
169169
var detail = "The HTTP resource that matches the request URI 'http://localhost/api/test' does not support the API version '42.0'.";
@@ -190,13 +190,13 @@ public async Task select_controller_should_return_404_for_unmatchedX2C_attribute
190190
var content = await response.Content.ReadAsProblemDetailsAsync();
191191

192192
// assert
193-
response.StatusCode.Should().Be( NotFound );
193+
response.StatusCode.Should().Be( BadRequest );
194194
response.Headers.GetValues( "api-supported-versions" ).Single().Should().Be( "1.0, 2.0, 3.0, 4.0" );
195195
response.Headers.GetValues( "api-deprecated-versions" ).Single().Should().Be( "3.0-Alpha" );
196196
content.Should().BeEquivalentTo(
197197
new ProblemDetails()
198198
{
199-
Status = 404,
199+
Status = 400,
200200
Title = "Unsupported API version",
201201
Type = ProblemDetailsDefaults.Unsupported.Type,
202202
Detail = detail,
@@ -255,7 +255,7 @@ public async Task select_controller_should_return_400_for_attributeX2Dbased_cont
255255
}
256256

257257
[Fact]
258-
public async Task select_controller_should_return_404_for_unmatchedX2C_conventionX2Dbased_controller_version()
258+
public async Task select_controller_should_return_400_for_unmatchedX2C_conventionX2Dbased_controller_version()
259259
{
260260
// arrange
261261
var detail = "The HTTP resource that matches the request URI 'http://localhost/api/test' does not support the API version '4.0'.";
@@ -283,13 +283,13 @@ public async Task select_controller_should_return_404_for_unmatchedX2C_conventio
283283
var content = await response.Content.ReadAsProblemDetailsAsync();
284284

285285
// assert
286-
response.StatusCode.Should().Be( NotFound );
286+
response.StatusCode.Should().Be( BadRequest );
287287
response.Headers.GetValues( "api-supported-versions" ).Single().Should().Be( "1.0, 2.0, 3.0" );
288288
response.Headers.GetValues( "api-deprecated-versions" ).Single().Should().Be( "1.8, 1.9" );
289289
content.Should().BeEquivalentTo(
290290
new ProblemDetails()
291291
{
292-
Status = 404,
292+
Status = 400,
293293
Title = "Unsupported API version",
294294
Type = ProblemDetailsDefaults.Unsupported.Type,
295295
Detail = detail,
@@ -413,7 +413,7 @@ public void select_controller_should_return_400_when_no_version_is_specified_and
413413
}
414414

415415
[Fact]
416-
public void select_controller_should_return_404_for_unmatched_action()
416+
public void select_controller_should_return_400_for_unmatched_action()
417417
{
418418
// arrange
419419
var configuration = AttributeRoutingEnabledConfiguration;
@@ -433,7 +433,7 @@ public void select_controller_should_return_404_for_unmatched_action()
433433
var response = selectController.Should().Throw<HttpResponseException>().Subject.Single().Response;
434434

435435
// assert
436-
response.StatusCode.Should().Be( NotFound );
436+
response.StatusCode.Should().Be( BadRequest );
437437
response.Headers.GetValues( "api-supported-versions" ).Single().Should().Be( "1.0, 2.0, 3.0, 4.0" );
438438
response.Headers.GetValues( "api-deprecated-versions" ).Single().Should().Be( "3.0-Alpha" );
439439
}

Diff for: src/AspNetCore/Acceptance/Asp.Versioning.Mvc.Acceptance.Tests/Http/given a versioned minimal API/when using an endpoint.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace given_a_versioned_minimal_API;
1111
public class when_using_an_endpoint : AcceptanceTest
1212
{
1313
[Theory]
14-
[InlineData( "api/order?api-version=0.9", NotFound )]
14+
[InlineData( "api/order?api-version=0.9", BadRequest )]
1515
[InlineData( "api/order?api-version=1.0", OK )]
1616
[InlineData( "api/order?api-version=2.0", OK )]
1717
[InlineData( "api/order/42?api-version=0.9", OK )]

Diff for: src/AspNetCore/Acceptance/Asp.Versioning.Mvc.Acceptance.Tests/Mvc/UsingAttributes/given a versioned Controller/when using a query string and split into two types.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ public async Task then_delete_should_return_405( string apiVersion )
8787
}
8888

8989
[Fact]
90-
public async Task then_get_should_return_404_for_an_unsupported_version()
90+
public async Task then_get_should_return_400_for_an_unsupported_version()
9191
{
9292
// arrange
9393

@@ -96,7 +96,7 @@ public async Task then_get_should_return_404_for_an_unsupported_version()
9696
var response = await GetAsync( "api/values?api-version=3.0" );
9797

9898
// assert
99-
response.StatusCode.Should().Be( NotFound );
99+
response.StatusCode.Should().Be( BadRequest );
100100
}
101101

102102
[Fact]

Diff for: src/AspNetCore/Acceptance/Asp.Versioning.Mvc.Acceptance.Tests/Mvc/UsingConventions/given a versioned Controller using conventions/when using a query string and split into two types.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public async Task then_get_should_return_200( string controller, string apiVersi
2929
}
3030

3131
[Fact]
32-
public async Task then_get_should_return_404_for_an_unsupported_version()
32+
public async Task then_get_should_return_400_for_an_unsupported_version()
3333
{
3434
// arrange
3535

@@ -38,7 +38,7 @@ public async Task then_get_should_return_404_for_an_unsupported_version()
3838
var response = await GetAsync( "api/values?api-version=4.0" );
3939

4040
// assert
41-
response.StatusCode.Should().Be( NotFound );
41+
response.StatusCode.Should().Be( BadRequest );
4242
}
4343

4444
[Fact]

Diff for: src/AspNetCore/Acceptance/Asp.Versioning.Mvc.Acceptance.Tests/Mvc/UsingNamespace/given a versioned Controller per namespace/when using a query string.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public async Task then_get_should_return_200( Type controllerType, string apiVer
3434
}
3535

3636
[Fact]
37-
public async Task then_get_should_return_404_for_an_unsupported_version()
37+
public async Task then_get_should_return_400_for_an_unsupported_version()
3838
{
3939
// arrange
4040

@@ -43,7 +43,7 @@ public async Task then_get_should_return_404_for_an_unsupported_version()
4343
var response = await GetAsync( "api/agreements/42?api-version=4.0" );
4444

4545
// assert
46-
response.StatusCode.Should().Be( NotFound );
46+
response.StatusCode.Should().Be( BadRequest );
4747
}
4848

4949
[Fact]

0 commit comments

Comments
 (0)