Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

6.3.0 #919

Unanswered
commonsensesoftware asked this question in Q&A
6.3.0 #919
Nov 19, 2022 · 1 comments · 1 reply
Discussion options

This is a minor update, which includes some routing improvements.

Features

All Platforms

  • ApiVersioningOptions.UnsupportedApiVersionStatusCode has been added to indicate the status code used when an API version doesn't match
    • The default value is 400, which has been the de facto from the beginning
    • Any status code can be used, but 400, 404, or 501 are generally the ones that make sense
    • Each response will continue to include ProblemDetails, which is always the same; regardless of status code
    • When versioning exclusively by URL segment or the incoming request URL is determined to yield an API version route parameter, this option is ignored and the response will always be 404
  • A Sunset Policy will always attempt be written when reporting API versions
    • Previously, it was only written on success because success is required for API-specific policies
    • A version-specific policy can be written even during failure since it is related to the version as a whole, regardless of API

Fixes

ASP.NET Core

  • IApiVersioningBuilder.AddMvc and IApiVersioningBuilder.AddApiExplorer now ensure dependent services are registered
    • AddApiExplorer, in particular, snagged a number of people that didn't realize they needed AddMvc
  • The ProblemDetails.Code extension is now correctly written in JSON as code
  • API versions are now reported when an endpoint is unmatched (Incomplete response when incorrect version requested #876, Requests with unsupported version don't return 4xx error code #918)
    • This should restore the behavior for unmatched endpoints that existed prior to 6.0
    • This is a best effort
      • No erroneous scenarios have been found, but there could be edge cases
      • The behavior is relying on the routing system to collate the metadata from endpoints that are already collated by name using their route templates
      • Attempts to create contrived configurations that could yield incorrect results were unsuccessful (which is good)

Breaking Changes

Restoring the unmatched endpoint behavior may break the expectations for those that have adopted 6.0. There's no good answer or time for this change to occur since this is an implementation detail that only manifests in behavior. Despite calling out the changes in the roadmap and release notes, several issues have been filed related to the change in 6.0. At the time, it didn't seem possible to retain that functionality, but it seems that - largely - it can be.

Ultimately, this change only affects APIs that are strictly concerned about whether the response will be 400 or 404 for client errors on unmatched versions. 400 will now revert to be the default case where you might have received 404. If it's important to you to retain the behaviors you've established while adopting 6.x, you can achieve that by setting:

ASP.NET Web API

(ApiVersioningOptions options) => options.UnsupportedApiVersionStatusCode = HttpStatusCode.NotFound

ASP.NET Core

(ApiVersioningOptions options) => options.UnsupportedApiVersionStatusCode = 404

Special note for .NET Core 3.1 users. There are edge cases where 404 is returned instead of 400. In reviewing the test cases, this was already a problem. It's unclear why that happens, but it appears to be a change or fix in the routing system in at least .NET 6.0 and above. This will be considered the expected behavior. It may be possible to change the behavior with middleware.


This discussion was created from the release 6.3.0.
You must be logged in to vote

Replies: 1 comment · 1 reply

Comment options

Hi! I'm trying to use version 6 with .net 6 + Odata and see that examples do not match wiki (https://github.com/dotnet/aspnet-api-versioning/wiki/API-Versioning-with-OData). Is wiki correct? PArticular, IModelConfiguration in the wiki are hardcoded, while in the example they seem to be auto-discovered. I am using Swashbuckle as well.

Also it's not clear from example - should I always list all the endpoints? https://github.com/dotnet/aspnet-api-versioning/blob/release/6.4/examples/AspNetCore/OData/SomeODataOpenApiExample/Program.cs#L38

You must be logged in to vote
1 reply
@commonsensesoftware
Comment options

The wiki is still behind. Documentation is important, but releases and bug squashes take priority with my limited capacity. This discrepancy is being tracked in #885. I'm actively working on updating it. I have future plans to reimagine the wiki as a more comprehensive documentation website.

The basic behaviors around IModelConfiguration hasn't changed. Matching types continue to be automatically discovered and used as the default provided to VersionedODataModelBuilder. You have the choice to add or remove additional instances to VersionedODataModelBuilder.ModelConfigurations. You may also use VersionedODataModelBuilder.DefaultModelConfiguration in lieu of, or in addition to, IModelConfiguration. The one thing that changed starting in 6.0 was where you typically use VersionedODataModelBuilder. You can still get it from DI, but you previously would have configured OData as part of the application middleware. In line with the changes in OData 8.0+, this now happens via OData configuration options, which is accessible via ODataApiVersioningOptions.ModelBuilder.

I'm not 100% sure what you mean by:

"...should I always list all the endpoints?"

I think what you are asking is whether you need to configure query options explicitly this way for every endpoint. The short answer is - no; it's fully up to you. The query options convention support is to fill the gap that cannot be expressed any other way. For example, the PeopleController.Get method looks something like:

[HttpGet]
[Produces( "application/json" )]
[ProducesResponseType( typeof( ODataValue<IEnumerable<Person>> ), Status200OK )]
public IActionResult Get( ODataQueryOptions<Person> options )
{
    // how can this imperative code surface information to OpenAPI? ¯/_(ツ)_/¯
    var validationSettings = new ODataValidationSettings()
    {
        AllowedQueryOptions = Select | OrderBy | Top | Skip | Count,
        AllowedOrderByProperties = { "firstName", "lastName" },
        AllowedArithmeticOperators = AllowedArithmeticOperators.None,
        AllowedFunctions = AllowedFunctions.None,
        AllowedLogicalOperators = AllowedLogicalOperators.None,
        MaxOrderByNodeCount = 2,
        MaxTop = 100,
    };
    // omitted for brevity
}

This OData action does not use Model Bound settings or [EnableQuery]; however, using ODataValidationSettings this way is completely valid. How do you surface this information? There is no convention or attribute that can be interrogated. The OData query options support enables a way to expose anything that would otherwise be imperatively set via ODataValidationSettings or ODataQuerySettings.

Aside: I noticed that you are referring to the partial OData example and BooksController doesn't actually have this validation. This a copy and paste error from the other OData example. I will update it. 😉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
🙏
Q&A
Labels
None yet
2 participants
Morty Proxy This is a proxified and sanitized view of the page, visit original site.